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

Hello Perl Monks,

I am trying to solve a text parsing problem where I would like to transform the following data:

Mon 0100 Mon 0700 Tue 0700 Wen 0100 Wen 0700 Thu 0100 Thu 0700 Fri 0100 Fri 0700 Sat 0100 Sun 0100 Sun 0700

to

Mon Tue Wen Thu Fri Sat Sun 0100 X X X X X X 0700 X X X X X X

It is basically transposing of columns where I would list the time field just once and for each day of the week found in the data, if the time existed, I would mark that column with X. If the time did not exist for that day, I would put a space.

I was able to solve the problem by doing:

perl -lane ' $h{$F[0]}++ or push @days, $F[0]; $h{$F[1]}++ or push @time, $F[1]; $data{$F[0],$F[1]}++ }{ print "\t\t", join "\t", @days; for $t (@time) { print $t, "\t\t", join "\t", map { $data{$_,$t} ? "X" : " " } +@days; } ' file

However, I was trying to learn chaining of map function and running in to some issues. My last attempt at chaining maps is:

perl -ane ' $h{$F[0]}++ or push @days, $F[0]; $h{$F[1]}++ or push @time, $F[1]; $data{$F[0],$F[1]}++ }{ print "\t\t", join "\t", @days; print "\n"; print for join "\t", map { $t = $_ ; (map { $data{$_,$t} ? "X" : " + " } @days) } @time; ' file

But I am struggling to print each element of time array just once and then iterate over the hash to print X or space if the key exists.

Looking forward to your wisdom.
Regards

Jaypal

Replies are listed 'Best First'.
Re: Trouble Chaining map function
by poj (Abbot) on Jun 14, 2014 at 20:23 UTC
    print map { $t = $_ ; join "\t", $t, ( map {$data{$_,$t} ? 'X' : ' '} @days ) ,"\n" } @time;
    poj

      Thanks Poj, this does help and answers my question. Appreciate your help.

Re: Trouble Chaining map function
by flowdy (Scribe) on Jun 14, 2014 at 20:25 UTC
    print join "\n", map { $t = $_ ; join("\t", $_."\t", map { $data{$_,$t} ? "X" : " " } @days ) } @time;
    This code differs from yours in several regards:
    • no redundant use of topicalizing single-scalar for to print
    • the time as first tab-separated item of the inner join
    • for each time an own line

    To me this looks like misusing map. Better use it solely to calculate results of values from a list by one or very few statements and no nested map, and putting the results into a new list or array at the same time.

      Thanks flowdy was the explanation. I agree with you, I wouldn't use this in a production code. I was just trying to understand how nesting can be done. I am of the type who would learn more by looking at a solution then reading through the doc. Your solution has shown me a clear way of nesting maps and I appreciate your help for that. :)

Re: Trouble Chaining map function
by LanX (Saint) on Jun 14, 2014 at 19:56 UTC
    You can always replace a foreach with a map by putting the complete loop body (including print and other maps) into the map and the list after.

    But your test for uniqueness is overly complicated and buggy in edge cases.

    Better just take simply the keys if %h and sort them.

    But if I were you I'd hardcode the weekdays into an array anyway.

    Cheers Rolf

    (addicted to the Perl Programming Language)

      Thanks Rolf, I will play around with your suggestions and update you if I come up with something interesting.

Re: Trouble Chaining map function
by NetWallah (Canon) on Jun 15, 2014 at 14:29 UTC
    Late to the party, but in the spirit of TIMTOWTDI, here is a non-nested map solution:
    perl -anE '$d ||={map {$_=>$x++} @wd=qw[Mon Tue Wen Thu Fri Sat Sun] +}; $F[1] and $v{$F[1]}->[$d->{$F[0]}] = "X" }{ say map{"\t$_"}@wd; say "$_\t",map {"$_\t"}@{$v{$_}} for sort keys %v' ts-data.txt

            What is the sound of Perl? Is it not the sound of a wall that people have stopped banging their heads against?
                  -Larry Wall, 1992

      Thank you NetWallah, that looks pretty intense :). I will have to spend some time trying to break it down and I appreciate your help in providing another approach.

      Thanks
      Jaypal