use Data::Dump 'pp'; # a "better" Data::Dumper my %obs; while ( ) { chomp; my ( $obs_num, $det, $x, $y ) = split; push @{ $obs{$obs_num}{$det} }, { x => $x, y => $y }; } #$obs{$obs_num}{$det}[$reading]{x} pp \%obs; __DATA__ 21 DET-2 896.657564735788 678.83860967799 21 DET-3 32.0939023018969 621.656550474314 21 DET-3 42.0741462550974 834.842294892622 21 DET-3 218.814294809857 450.606540154849 21 DET-3 228.88830316475 625.939190221948 21 DET-3 630.472705847461 220.839350101088 21 DET-5 152.988115061449 156.31861287082 88 DET-0 114.871177986263 212.959076023136 88 DET-0 219.421725079137 710.314439572696 88 DET-0 257.837516726887 594.376577764894 88 DET-1 119.630462310966 260.433234269099