Perl6: matching items in a list to another list

I have a list of L numbers. There is another list of numbers M. I need to return a list of L ' numbers found in both L and M.

Change Mathematically, I'm looking for a 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 this:

 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 reaches the goal, I was wondering if there is an idiomatic way for Perl6 to do this?

Some background: I tried to learn Perl6 and Python together and solve the same puzzles in both languages. Python offered a particularly nice solution to the above problem. For my beginner eyes at least :)

+5
source share
3 answers

Depending on the exact semantics you are looking for, Bag operations can only be a 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; 

displayed:

 9 1(2) 2 

This is a Bag line containing three keys '9' , '1' and '2' , whose corresponding values ​​(number of repetitions) are integers 1 , 2 and 1 .

To get Perl 6 to create a list from a bag, each key repeated the number of times indicated by its associated value, use the .kxxv method:

 .kxxv.put with L.BagM.Bag; 

displayed:

 9 1 1 2 

(The mnemonic for the kxxv method is that it is k for the “key”, then xx by analogy with xx and finally v for the “value.” This makes sense if you think about it.)

But perhaps the bag will not do. For example, perhaps the order of the elements in the result matters - do you need 9 1 2 1 and not 9 1 1 2 ? I will continue this answer if the bag is not suitable for the right path.

+6
source

You can do this 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 return the bag back to the array using .kxxv .

 my @match-list = $matched.kxxv; say @match-list; 

Output:

 [9 1 1 2] 

(If you do not need duplicates, use sets instead of bags).

+6
source

You can try the following:

 use v6; my @some_numbers = 3, 1, 4, 1, 5, 9, 2, 6; my @to_match = 9, 7, 1, 2, 1, 1; my %seen = map { $_ => 1 }, @to_match; my @matched = grep { %seen{$_}:exists }, @some_numbers; say @matched; 

Output

 [1 1 9 2] 
+1
source

Source: https://habr.com/ru/post/1266184/


All Articles