ImJustAFriend has asked for the wisdom of the Perl Monks concerning the following question:

Hi again all. Thank to your awesome help, I am rolling right along. I have one more part (I think) to accomplish. I've gotten my parsed log into this kind of format:
label1=value1 label2=value2 ... labeln=valuen
I have an array that represents the CSV layout from another program that my output has to match. There are 900+ elements in the array, but I will never see 900+ lines of parsed output. So I need to loop through the array and look in all my parsed output lines to see if array element = "labeln" in any of the output lines. If it does, I need to print "valuen;" to my CSV output file. If not,, I need to print ";" to my CSV output file, so there would either be a value or a semicolon for each item in the format array. I have tried map, grep, regex, smartmatch, putting all the labeln into an array... I am out of ideas. Anyone know how I can successfully accomplish this task? Thanks!!

Replies are listed 'Best First'.
Re: Determine if array value in string results
by 1nickt (Canon) on Nov 21, 2018 at 18:16 UTC

    Hi, the classic technique for finding out whether an element of one array is present in another array is to make a hash lookup table.

    use strict; use warnings; my @to_be_searched = qw/ lots of elements /; my @to_find = qw/ fewer elements /; my %lookup = map { $_ => 1 } @to_be_searched; for my $element ( @to_find ) { if ( exists $to_be_searched{ $element } ) { # do something } else { # do other thing } }
    (In your case you may need to do something to $element (capture part of it via regexp?) and use the product of that to search the lookup table.)

    Hope this helps!


    The way forward always starts with a minimal test.
      Thank you 1nickt I implemented your idea, slightly modified based on my situation, so it looks like this:
      if ( $RESULT eq "" ) { print DEBUG1 "Line is \"" . $line ."\"\n"; my $action = substr($ACTION, 0, 1); open OUT4, ">>", $csvtogo or die "Could not op +en OUT4: $!\n"; if ( $line =~ /parameters\ after\ change/ ) { #Start of block to manage $inblock = 1; next; } # Skip handling line unless we are in a block next unless ( $inblock ); if ( $line =~ /NRG\ location/) { print OUT4 "$timestamp;$action;"; # Block ends here # Process all blocked lines stored in +@blocklines my ($k, $v); my @fields; my %lookup = map { $_ => 1 } @csvfield +list; foreach my $bline (@blocklines) { print DEBUG1 "bline: \"$bline\ +"\n"; my ($k, $v) = split '=', $blin +e; push @fields, $k; } print DEBUG Dumper (\@fields); for my $element ( @fields ) { if (exists $lookup{$element}) +{ print OUT4 "yes;"; } else { print OUT4 ";"; } } print OUT4 "\n" #Cleanup block now that it has been pr +ocessed @blocklines = (); $inblock = 0; next; } # Just a line we want to process within the bl +ock # Push it into @blocklines so we can process i +t push @blocklines, $line; next; }
      When I look at my results file (OUT4), I see this (in part):
      2018_11_20-11_15_58;C;;yes;;;; 2018_11_20-11_15_58;C;yes;yes;yes;yes;yes;yes;yes;yes;yes;yes;yes;yes; +yes;yes;yes;yes;yes;yes;;;;;yes;yes;yes;yes;yes;yes;yes;;;;;;;;;;; 2018_11_20-11_15_58;C;;; 2018_11_20-11_15_58;C;yes;yes;yes;yes;; 2018_11_20-11_15_58;C;yes;yes; 2018_11_20-11_15_58;C;yes;yes; 2018_11_20-11_15_58;C;yes;yes; 2018_11_20-11_15_58;C;yes;;;; 2018_11_20-11_15_58;C;yes;;;;; 2018_11_20-11_15_58;C;yes; 2018_11_20-11_15_58;C;yes;yes;yes;; 2018_11_20-11_44_51;C;;yes;;;; 2018_11_20-11_44_51;C;yes;yes;yes;yes;yes;yes;yes;yes;yes;yes;yes;yes; +yes;yes;yes;yes;yes;yes;;;;;yes;yes;yes;yes;yes;yes;yes;;;;;;;;;;;
      Each line above should be MUCH longer. When I print @fields to DEBUG, I get this (in part):
      $VAR1 = [ 'algorithmPosition', 'authenticationSubscriberType', 'k4id', 'OP_id', 'authKey' ]; $VAR1 = [ 'mobileNetworkCodeId', 'mobileCountryCodeId', 'chargingGatewayFuncHost', 'chargingGroup', 'S6aRoamingRestrictionType', 'pcscfServerName', 'maxRequestedBandwidthUL', 'maxRequestedBandwidthDL', 'epsAccessSubscriptionType', 'epsAccessSubscriptionType', 'odbSpecificToPs', 'psRoamingRestrictionType', 'chargingCharacteristics', 'odbCustoPremRateCalls', 'odbOutgoingCalls', 'accessRestrictionData', 'networkAccessMode', 'mSubIdentificationNumberId', 'GcsServiceProfile', 'OdbServiceProfile', 'MainSNwithBearerService', 'MainSNwithBearerService', 'cwTSSpeechActivationFlag', 'callWaitingProvisionedFlag', 'clipProvisionedFlag', 'mptyProvisionedFlag', 'callHoldProvisionedFlag', 'clirProvisionedFlag', 'csRoamingRestrictionType', 'eps3gppRestrictionListNum', 'psRestrictionListNum', 'csRestrictionListNum', 'packetMsAddressList', 'packetMsAddressList', 'framedPoolSetList', 'framedPoolSetList', 'epsApnContextSetList', 'epsApnContextSetList', 'epsServiceProfile' ]; $VAR1 = [ 'serverCapIdx', 'chargingIdx' ]; $VAR1 = [ 'authEntryType', 'hlrIndicator', 'protocolCap', 'authSchema', 'imsi' ]; $VAR1 = [ 'puidType', 'unregSvcInd' ]; $VAR1 = [ 'puidType', 'unregSvcInd' ]; $VAR1 = [ 'puidType', 'unregSvcInd' ];
      Do I need to include the whole 900+ item array as well? Or can you see what's going on based on what you see here? Thanks again!

        Hi again. First, no way you should be producing your output like that. That kind of manual jiggery-pokery is fraught with pitfalls and error vectors. You need to build up a data structure known as an array of arrays representing your output, and then convert it to the delimited file using Text::CSV or Text::CSV_XS.

        As to your problem: you are building a lookup table from the wrong structure. If what you want to do is check all fields in @csvfieldlist to see which are present in @fields, and record a null value for those that are not, you need to make the lookup table from @fields and loop through the larger list.

        use Text::CSV_XS; my @rows; for my $line ( @something ) { if ( $line =~ /NRG\ location/) { my @row; my @fields; foreach my $bline (@blocklines) { my ($k, $v) = split '=', $bline; push @fields, $k; } my %lookup = map { $_ => 1 } @fields; for my $field ( @csvfieldlist ) { if ( exists $lookup{ $field } ) { push @row, 'yes'; } else { push @row, undef; } } push @rows, \@row; } } csv (in => \@rows, out => "file.csv", sep_char=> ";");

        Hope this helps!


        The way forward always starts with a minimal test.
Re: Determine if array value in string results
by hippo (Archbishop) on Nov 21, 2018 at 18:13 UTC
Re: Determine if array value in string results
by james28909 (Deacon) on Nov 21, 2018 at 17:48 UTC

    Can you show us the code that you have tried? The code thats not working?

    What it sounds like to me is that you are trying to loop through an array with 900+ elements and find the ones that match "valuen".

    use strict; use warnings; my @array = qw(valuen valued valuec valueq values); for (@array) { if (/valuen/) { print; } else { print ";"; } }