I have a list of numbers L. There is another list of numbers M. I need to return a list L' of numbers found in both L and M.
Edit: Mathematically, I am looking for Multiset intersection.
Example:
L = 3,
1
, 4,1
, 5,9
,2
, 6
M =9
, 7,1
,2
,1
, 1
L' = 9, 1, 2, 1
I wrote the following code for that:
my @some-numbers = 3, 1, 4, 1, 5, 9, 2, 6;
my @to-match = 9, 7, 1, 2, 1, 1;
my @matched;
my %histogram;
for @some-numbers -> $n { %histogram{$n}++ };
for @to-match -> $n {
next if not defined %histogram{$n};
if %histogram{$n} > 0 {
push @matched, $n;
%histogram{$n}--;
}
};
say @matched;
While it achieves the purpose, I was wondering whether there was an idiomatic Perl6 way of doing this?
Some background: I have been trying to learn Perl6 and Python together, and solve the same puzzles in both the languages. Python offered a particularly pleasing solution for the above problem. To my beginner eyes at least :)
You can do it with bags:
my $some-numbers = bag 3, 1, 4, 1, 5, 9, 2, 6;
my $to-match = bag 9, 7, 1, 2, 1, 1;
my $matched = $some-numbers ∩ $to-match;
say $matched;
Output:
bag(9, 1(2), 2)
You can turn the bag back into an array with .kxxv
.
my @match-list = $matched.kxxv;
say @match-list;
Output:
[9 1 1 2]
(If you don't care about duplicates, use sets instead of bags.)
Depending on the precise semantics you're looking for, Bag operations might be just the ticket:
my \L = 3, 1, 4, 1, 5, 9, 2, 6;
my \M = 9, 7, 1, 2, 1, 1;
.put with L.Bag ∩ M.Bag;
displays:
9 1(2) 2
This is the stringification of a Bag
containing the three keys '9'
, '1'
, and '2'
whose respective values (repeat counts) are the integers 1
, 2
, and 1
.
To get Perl 6 to produce a list from a bag with each key repeated the number of times indicated by its associated value, use the .kxxv
method:
.kxxv.put with L.Bag ∩ M.Bag;
displays:
9 1 1 2
(The mnemonic for the kxxv
method is that it's k
for "key" then xx
in analogy with the xx
repetition operator and finally v
for "value". It sorta makes sense if you think about it.)
But perhaps a bag won't do. For example, perhaps the order of elements in the result matters -- you need 9 1 2 1
and not 9 1 1 2
? I'll extend this answer if a bag isn't the right way to go.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With