A piggy bank of commands, fixes, succinct reviews, some mini articles and technical opinions from a (mostly) Perl developer.

Jump to

Quick reference

Showing posts with label algorithm. Show all posts
Showing posts with label algorithm. Show all posts

Determine differences in an array with Perl

Not just checking whether or not two arrays are the same, but finding out how they are different, i.e. what has been added and what has been taken away:

use Algorithm::Diff 'sdiff';
use Data::Dumper;

my @a = (1, 2, 3, 4);
my @b = (2, 3, 4, 5);

my @c = sdiff(\@a, \@b);

print Dumper(\@c);

Output:

$VAR1 = [
          [ '-',  1, '' ],
          [ 'u',  2,  2 ],
          [ 'u',  3,  3 ],
          [ 'u',  4,  4 ],
          [ '+', '',  5 ]
        ];

You can see that 1 has a '-' indicating it has been removed, and 5 has a '+' indicating it has been added. The other items have a 'u', indicating they are unchanged.

(source)

However, if comparing (a b c) with (c b a), Algorithm::Diff::sdiff will fail to realise that nothing has been added or removed. A simpler algorithm might be:

sub determine_changes {
    my ($old, $new) = @_;

    # Compare two lists
    my %old_lookup = map { $_ => 1 } @$old;
    my %new_lookup = map { $_ => 1 } @$new;
    my @added = grep { ! $old_lookup{$_} } @$new;
    my @removed = grep { ! $new_lookup{$_} } @$old;

    my @changes;
    push @changes, map { { item => $_, operation => 'add'    } } @added;
    push @changes, map { { item => $_, operation => 'remove' } } @removed;

    my @sorted_changes = sort { $a->{item} cmp $b->{item} } @changes;
    return \@sorted_changes;
}

Perl: Subtract one list from another list

my @difference = grep { not ($_ ~~ \@small_array) } @big_array;


# ~~ is the smart matching operator

Sorting in Perl

Custom sorting method:

@sorted = sort { 
  if ($a eq 'aardvark') { return 1; }
  elsif ($b eq 'aardvark') { return -1; }
  else { return $a cmp $b; } 
} @words;

Remember to test for the special case for both $a and $b.


Thanks

Combinations, permuations and iterations

To generate all combinations or permutations of a fixed list, use Math::Combinatorics

To generate sequential values for a set of slots, e.g. all binary numbers, or the number of 'max_results' for several modules do this:

  1. add one to the first slot
  2. if that takes it over the maximum, set it to zero and add one to the next slot
  3. repeat step 2 until you reach all zeroes
  4. if all zeroes, you are finished.