Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
PerlMonks  

split (grep)

by tbone654 (Beadle)
on Oct 23, 2014 at 19:52 UTC ( [id://1104807]=perlquestion: print w/replies, xml ) Need Help??

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

This is driving me crazy... I'm ultimately trying to read in two lists, one with a single column of ordered names... The second list is a column of names with a comma separated (this test script is using semi-colons) value after the name...
If I were able to do this in unix I would be:

grep -f file1 file2
Which is ok, but file1 loses it's order to file2, and what I really want to do is print values from file2 next to the order in file1... so I need to split off values and print the results next to the members of file1 where there is a match...
But it seems like today I'm too stupid to figure out how to do the split command correctly... Or, other... I could just print the line from list2, but there could be many values and I need to split them out to do math on them after I figure out the problem with split... perldoc -f split tells me it's returning the number of times each line succeeds, where I need to be able to manipulate the results. I've been searching the site for something similar, with no success. Thank you for any help in advance.

my $a; my @foo = qw/tom steve bill roger bob/; my @bar = qw/roger;99 steve;56 ted;88 tom;54/; for($a=0;$a<@foo;$a++) { printf("%s %s\n",$foo[$a],grep(/$foo[$a]/,@bar)); } print "----\n"; for($a=0;$a<@foo;$a++) { # printf("%s\n", grep(/$foo[$a]/,@bar) ); printf("%s\n", (split /;/, grep(/$foo[$a]/,@bar))[0] ); } --output before split-- tom tom;54 steve steve;56 bill roger roger;99 bob ---- tom;54 steve;56 roger;99 --output using split-- tom tom;54 steve steve;56 bill roger roger;99 bob ---- 1 1 0 1 0

Replies are listed 'Best First'.
Re: split (grep)
by Laurent_R (Canon) on Oct 23, 2014 at 20:35 UTC
    If your list is short, using grep on an array is fine. But this means that you are reading the whole array (second list) each time, which is quite inefficient if the list is long. In that case, using a hash for the second list is a better solution. Re-using toolic's data sample, it could look like this:
    use warnings; use strict; my @foo = qw/tom steve bill roger bob/; my %bar = (roger => 99, steve => 56, ted => 88, tom => 54); for my $name (@foo) { print "$name : $bar{$name} \n" if exists $bar{$name}; }
    which prints:
    tom : 54 steve : 56 roger : 99
    I understand that you are reading your data from files, so populating a hash is not more complicated than filling an array. You just have to do the split before populating the hash, instead of doing it later.

    Actually, even with a short list, I think that I would probably prefer the hash-based solution.

      I understand why the hash-based solution makes more sense for performance. Especially in a "fancy" solution. I guess I just want to be able to split on the grep statement as an argument if I needed to... If I can...

      This started out as a one liner "brute force" grep replacement in case I needed more than a single or just a few members of the first list...

      perl -ne 'next if(!/tom/ && !/steve/) ; printf("%10s %5s",(split/;/)[0 +,1]);' list.txt tom 54 steve 56

      Thank you for the input

        I settled on this for the moment, as it preserves the order of the first list, which is a requirement.

        @foo = qw/tom steve bill roger bob/; @bar = qw/roger;99 steve;56 ted;88 tom;54/; foreach $line(@foo){ foreach $line1(@bar){ @split1=(split/;/,$line1); if($line =~ $split1[0]){ printf("%5s %3s\n",$split1[0],$split1[1]); } } } __END__ tom 54 steve 56 roger 99
        Thank you for the suggestions

Re: split (grep)
by toolic (Bishop) on Oct 23, 2014 at 20:04 UTC

    Tip #1 from the Basic debugging checklist: warnings

    tom tom;54 steve steve;56 Missing argument in printf at ... bill roger roger;99 Missing argument in printf at ... bob ---- 1 1 0 1 0

    UPDATE: Is is this more like what you want?

    use warnings; use strict; my @foo = qw/tom steve bill roger bob/; my @bar = qw/roger;99 steve;56 ted;88 tom;54/; for my $name (@foo) { my @match = grep { /$name/ } @bar; print "$name $match[0]\n" if @match; } __END__ tom tom;54 steve steve;56 roger roger;99

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1104807]
Approved by lidden
Front-paged by toolic
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others romping around the Monastery: (3)
As of 2024-04-19 04:09 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found