Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

Joining Arrays?

by Jaganath (Initiate)
on Dec 20, 2008 at 21:07 UTC ( #731808=perlquestion: print w/replies, xml ) Need Help??
Jaganath has asked for the wisdom of the Perl Monks concerning the following question:

Hi folks - I'm a perl FNG and I have a question about joining and outputing arrays. I have two arrays (lines read in from txt files and split on \n). What I need to do is join them, but in itterations.
i.e., the first array contains urls, say
http://www.something.com/blah.aspx?code=
and
http://www.somethingelse.com/stuff.aspx?thing=

The second array contains product codes, say
375035304
564564774
346464646

I need to end up with an array containing an entry for each url/code combination -i.e

http://www.something.com/blah.aspx?code=375035304
http://www.something.com/blah.aspx?code=564564774
http://www.something.com/blah.aspx?code=346464646
http://www.somethingelse.com/stuff.aspx?thing=375035304
http://www.somethingelse.com/stuff.aspx?thing=564564774
http://www.somethingelse.com/stuff.aspx?thing=346464646

So far nothing I've tried works (I'm only about 12 hours into my perl voyage so please forgive my ignorance :0)

Any help would be very welcome - here's my code so far:
#!/usr/bin/perl

#open and assign urls file
open (URLS, "urls.txt") || die("Couldn't open file!");
@raw_urls=<URLS>;
close(URLS);

#open and assign isbn/prod code file
open (CODES, "data.txt") || die("Couldn't open file!");
@raw_codes=<CODES>;
close(CODES);

# loop through urls, split out and dump in array
foreach $urls (@raw_urls)

{
(@url)=split(\n, $urls);
print @url; \n #test output
}
# loop through codes, split out and dump in array
foreach $codes (@raw_codes)
{
(@code)=split(\n, $codes);
print @code; \n #test output

}

Replies are listed 'Best First'.
Re: Joining Arrays?
by Lawliet (Curate) on Dec 20, 2008 at 21:40 UTC

    Well, without indentation your code is difficult to read. Try wrapping it in <c></c> tags and format it to be readable by those unfamiliar with it. From a quick glance there are many errors (such as putting a \n after the semi-colon. Using warnings will catch that.)

    That being said, try (actually, don't try it -- just get inspiration from it :P)

    #!/usr/bin/perl use warnings; use strict; my @final; # Joined lines will be in here open(URLS, '<', 'urls.txt') or die $!; # I can never remember if < is +read chomp(my @urls = <URLS>); # Every line of URLS is a different element +in @urls close URLS; open(CODES, '<', 'data.txt') or die $!; chomp(my @codes = <CODES>); close CODES; foreach my $url (@urls) { # For every element (line) in @urls, foreach my $code (@codes) { # and for every element in @codes, push @final, $url$code; # append the two and push it into @fin +al } }

    The first three lines should be in all your Perl programs. Using warnings will catch a lot of stupid mistakes you will make and using strictures will keep you from making a lot of stupid mistakes. I think the rest of the code is self explanatory.

    Updated with more comments.

    Update 2: Ikegami reminded me (thanks ikegami :D) that you must chomp() each element of the arrays before you push it into @final to remove the newline at the end. I'll update my code to show this soon. Done (with inspiration from kyle :P).

    And you didn't even know bears could type.

      can never remember if < is read

      It's just like the shell. It's an arrow that indicates flow.

      open(URLS, '<', 'urls.txt') | | | | +----<-------+ from the file into the handle

        :O

        That is my face right now after being bewildered by your explanation :P

        -.- is my face right after that because I did not make the connection at first.

        And you didn't even know bears could type.

Re: Joining Arrays?
by kyle (Abbot) on Dec 20, 2008 at 21:55 UTC

    You could do it with nested maps:

    open my $url_fh, '<', 'urls.txt' or die "Can't read 'urls.txt': $!"; chomp( my @urls = <$url_fh> ); close $url_fh or die "close() failed: $!"; open my $code_fh, '<', 'data.txt' or die "Can't read 'data.txt': $!"; chomp( my @codes = <$code_fh> ); close $code_fh or die "close() failed: $!"; my @joined = map { my $url = $_; map { $url . $_ } @codes } @urls;

    Note that this actually creates an array for the results, while a foreach solution won't.

      There's something about nested maps that strikes me as unsavory. Sure, there's nothing syntactically wrong with it, but then there's nothing syntactically wrong with a sentence like "The cat the dog the man hit bit died."

      In the case of nested maps, keeping track of what each $_ is holding involves an extra cognitive load. It's simply that it takes the reader a fair bit longer than normal to figure out the intent, and for that reason, I'd prefer to avoid it.

        I agree with that. It would be nice if map (and grep) could take a variable like foreach does.

        # this doesn't work my @joined = map my $url { map my $code { $url . $code } @codes } @urls;
        ...nothing syntactically wrong with a sentence like "The cat the dog the man hit bit died."

        Ah. Fluent reverse Polish. Or is it Yoda egg-nog on (too much) ?

        I've tried to parse this... putting the brackets back in I get: died(the cat bit (the dog hit the man)) -- I'm assuming: (a) that each 'the' is part of the name of each object/subject; (b) that 'died' is a unary (intransitive); and (c) that 'bit' and 'hit' are binary operations (transitive).

        So much for syntax... semantics-wise, assuming that the 'hit' and 'bit' operators return the object modified by the operation inflicted upon it by the subject...

        ...no wonder the man died. What on earth had he done to upset both the cat and the dog ? And what did the dog hit him with ?

        Of course, being reverse polish the operators may themselves be reverse -- so the cat gets it because the man hit the dog ? What kind of twisted world is this ?

      Perl6 provides a pretty handy way to do this. It has X which I beleive is pronounced "cross" so that you can do: (source)

      use v6; my @urls = ('http://www.something.com/blah.aspx?code=', 'http://www.somethingelse.com/stuff.aspx?thing='); my @ids = ('375035304','564564774','346464646'); my @combined = (@urls X @ids).map: {$^a ~ $^b}; .say for @combined;

      Which outputs the following on Rakudo already:

      http://www.something.com/blah.aspx?code=375035304 http://www.something.com/blah.aspx?code=564564774 http://www.something.com/blah.aspx?code=346464646 http://www.somethingelse.com/stuff.aspx?thing=375035304 http://www.somethingelse.com/stuff.aspx?thing=564564774 http://www.somethingelse.com/stuff.aspx?thing=346464646

      The $^a and $^b in the map block tell it to take two elements at a time, while the X in the parenthesis tells it to cross join the two arrays. Very very handy for this kind of thing.


      ___________
      Eric Hodges
        Such cross-like operations are common enough that there is also a cross meta-operator in Perl 6 to trick an ordinary binary operator into doing it. So instead of saying:
        my @combined = (@urls X @ids).map: {$^a ~ $^b};
        you can just say
        my @combined = @urls X~ @ids;
        That is, just put X in front of the ordinary operator to make it a cross operator.

        Update: changed old X~X form to new X~ form.

        Interesting. But, unfortunately I am using perl 5.8. Where can I read about the new arrivals in perl 6 version?

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://731808]
Approved by friedo
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others perusing the Monastery: (5)
As of 2018-10-16 10:19 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    When I need money for a bigger acquisition, I usually ...














    Results (84 votes). Check out past polls.

    Notices?