 <p>Here is a run-down of how that code works.</p> <ul> <li><p>Define <code>$result</code> and <code>$df</code>. And for some odd reason, try to assign an empty list to them, even though it doesn't do anything.</p> <pre><code>my $result =(); my $df = (); </code></pre></li> <li><p>Read a line from <code>FILE</code> file-handle, and put it into <code>$_</code>, for every line.</p> <pre><code>while (&lt;FILE&gt;) { </code></pre></li> <li><p>Split <code>$_</code> on white-space, removing first element if it would be blank.</p> <pre><code> my @row = split; </code></pre></li> <li><p>Set <code>$id</code> to the last element of <code>@row</code>.</p> <pre><code> my $id = $row[-1]; </code></pre></li> <li><p>Loop on all indexes of <code>@row</code> except last two, and set <code>$i</code> to the index. This would have been easier to write if the previous operation had been to <a href="http://perldoc.perl.org/functions/pop.html"><code>pop</code></a> the last element of the end. I think it should have been <code>$#row-1</code> instead.</p> <pre><code> for my $i(0 .. $#row - 2) { </code></pre></li> <li><p>Split element of <code>@row</code> at location <code>$i</code>, by <code>:</code>.</p> <pre><code> my @group = split(/\:/, $row[$i]); </code></pre></li> <li><p>Index into <code>%result</code> (not <code>$result</code>).</p> <p>First by <code>$id</code>, then by first element of <code>@group</code>. Setting it to the second value of <code>@group</code>.</p> <pre><code> $result{$id}{$group[0]}=$group[1]; </code></pre></li> <li><p>Increment element of <code>%df</code> (not <code>$df</code>), by the first value of <code>@group</code>. It ends up setting it to <code>1</code> if it didn't previously exist.</p> <pre><code> $df{$group[0]}++; </code></pre></li> <li><p>End of <code>for</code> then <code>while</code> loops.</p> <pre><code> } } </code></pre></li> </ul> <hr> <p>This is how I would have written it.</p> <pre><code>use strict; use warnings; use autodie; my $filename = 'filename'; open my $fh, '&lt;', $filename; my %result; my %df; while (&lt;$fh&gt;){ my @row = split; my $id = pop @row; pop @row; # I assume this should be removed. for my $pair (@row){ my($key,$value) = split(':', $pair); $result{$id}{$key} = $value; $df{$key}++; } } </code></pre>