Hi all,
I have a method which returns two arrayrefs: one is an array of
hashes, and the other an array of arrays. I'm writing a test harness
for this method, so I put together some testcases and expected
results. I don't care what order the arrays are in; I only care that
the arrayrefs returned by the function contains exactly the same set
of values as the expected results.
Something like this:
# embeddings is an array of hashes, $anchors is an array of arrays
my ($embeddings, $anchors) = $embedder->embed($subgraph);
my $expected => {
embeddings => [
{
a => '1',
b => '2',
},
{
a => '1',
b => '3',
},
{
a => '2',
b => '3',
},
],
anchors => [
['1','2'],
['2','3'],
['1','3'],
],
},
use Test::More tests => 2;
is_deeply($embeddings, $expected->{embeddings},
"embeddings match");
is_deeply($anchors, $expected->{anchors},
"anchors match");
...except that I don't care if the actual and expected array referents
are in a different order, only that they contain the same items.
My first thought is to sort the arrays according to some arbitrary
convention and use is_deeply() as above; but I'm stuck as to how to
write a sort ordering well. I'm thinking I should sort the array of
hashes by lexicographical ordering of hash values, with
lexicographical significance determined by sorted key order, and sort
the array of arrays by simple lexicographical order. I have something
like this:
use List::MoreUtils qw(pairwise);
# lexicographical comparison function for lists of hashes
sub lexhash {
my @seq_a = map {$a->{$_}} sort keys %$a;
my @seq_b = map {$b->{$_}} sort keys %$b;
for my $pair (pairwise {[$a,$b]} @seq_a, @seq_b) {
return $pair->[0] cmp $pair->[1] if $pair->[0] cmp $pair->[1];
}
return 0;
}
# lexicographical comparison function for lists of arrays
sub lexarray {
for my $pair (pairwise {[$a,$b]} @$a, @$b) {
return $pair->[0] cmp $pair->[1] if $pair->[0] cmp $pair->[1];
}
return 0;
}
is_deeply([sort lexhash @$embeddings], [sort lexhash
@{$expected->{embeddings}}],
"embeddings match");
is_deeply([sort lexarray @$anchors], [sort lexarray @{$expected->{anchors}}],
"anchors match");
This works and does what I want, but it feels hacky and I'm not
entirely happy about it. I have these questions:
1. Is there a "set" type which holds aggregate data and doesn't care
about order, which I could use to compare these results for equality?
2. If not, is my solution to the problem a reasonable design? If not,
what better way could I do it?
3. If it's a reasonable design, is there any way my implementation of
it could be improved? In particular, could it be made more readable?
I'm not convinced that I could work out what this code does next week,
let alone in six months time.
Phil
--
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]
http://learn.perl.org/