#!/usr/bin/perl -w use strict; use Data::Dumper; sub main { my @filenames = @ARGV; my @times; my ($file, $tr, $dir, $day, $k); my (%seen, %times); for $file (@filenames) { push @times, handle_file($file); } for $tr (@times) { for $dir (keys %$tr) { for $day (keys %{$tr->{$dir}}) { $seen{$dir . $day}++; } } } for $k (keys %seen) { if ($seen{$k} > 1) { die "More than one hashref had the same day/dir combination: $k"; } } for $tr (@times) { for $dir (keys %$tr) { for $day (keys %{$tr->{$dir}}) { $times{$dir}{$day} = $tr->{$dir}{$day}; } } } output(%times); } sub splitline ($) { my $l = shift; chomp $l; return split /\t/, $l; } sub zipper (\@\@) { my ($a, $b) = @_; my (@a, @b); my @result; @a = @$a; @b = @$b; while (@a and @b) { push @result, shift(@a), shift(@b); } if (@a) { push @result, @a; } elsif (@b) { push @result, @b; } return @result; } sub handle_file { my $filename = shift; my %times; my (@timepoints, @days, @linenos, @tmpdays, @times); my ($curline, $day, $dir, $tp); open(CSV, $filename); @timepoints = splitline(); @days = splitline(); @linenos = splitline(); $curline = 4; push @linenos, -1; @tmpdays = @days; $dir = 1; while () { if ($curline++ == $linenos[0]) { if (@tmpdays == 0) { @timepoints = reverse @timepoints; @tmpdays = @days; $dir++; } shift @linenos; $day = shift @tmpdays; for $tp (@timepoints) { @{$times{$dir}{$day}{$tp}} = (); } } chomp; @times = split /\t/; for $tp (@timepoints) { push @{$times{$dir}{$day}{$tp}}, shift @times; } } close(CSV); return \%times; } sub output (%) { my (%times) = @_; my (%seentp, %seendays); my (@timepoints, @days); my ($dir, $day, $tp); # Pull the timepoints out of the structure. for $dir (keys %times) { for $day (keys %{$times{$dir}}) { $seendays{$day}++; for $tp (keys %{$times{$dir}{$day}}) { $seentp{$tp}++; } } } # Sort the timepoints. The order is dictated by the first direction; # order of the second direction is swapped so both arrays point the same # way. @timepoints = sort { my $result = cmptimes($a, $b, 1, \%times); if ($result == 0) { $result = cmptimes($b, $a, 2, \%times); } $result; } keys %seentp; @days = keys %seendays; # Time points are easy now. print join("\t", @timepoints), "\n"; # As are days. print join("\t", @days), "\n"; my $trips = ""; my @startlines; my $line = 4; $dir = 1; for my $day (@days) { # Remember where this block of data started. push @startlines, $line; while (more_data($dir, $day, %times)) { for my $tp (@timepoints) { if (exists $times{$dir}{$day}{$tp}) { $trips .= shift(@{$times{$dir}{$day}{$tp}}) . "\t"; } else { $trips .= "-----\t"; } } chop($trips); $trips .= "\n"; $line++; } } # Kinda bad, but it'd be more work to actually write a subroutine for it. $dir = 2; @timepoints = reverse @timepoints; for $day (@days) { # Remember where this block of data started. push @startlines, $line; while (more_data($dir, $day, %times)) { for $tp (@timepoints) { if (exists $times{$dir}{$day}{$tp}) { $trips .= shift(@{$times{$dir}{$day}{$tp}}) . "\t"; } else { $trips .= "-----\t"; } } chop($trips); $trips .= "\n"; $line++; } } print join("\t", @startlines), "\n"; print $trips; } sub cmptimes ($$$\%) { my ($a, $b, $dir, $tr) = @_; my $i; my @days = keys %{$tr->{$dir}}; my $day = $days[0]; if (exists $tr->{$dir}{$day}{$a} and exists $tr->{$dir}{$day}{$b}) { for ($i = 0; $i < $#{$tr->{$dir}{$day}{$a}}; $i++) { if (${$tr->{$dir}{$day}{$a}}[$i] ne "-----" and ${$tr->{$dir}{$day}{$b}}[$i] ne "-----") { last; } } if ($i < $#{$tr->{$dir}{$day}{$a}}) { # Because of the format of the data, string compare will work. return ${$tr->{$dir}{$day}{$a}}[$i] cmp ${$tr->{$dir}{$day}{$b}}[$i]; } } return 0; } sub more_data { my ($dir, $day, %times) = @_; my @keys = keys %{$times{$dir}{$day}}; my $count = @{$times{$dir}{$day}{$keys[0]}}; return $count > 0; } main;