Raku Bags
In Perl there’s a common idiom for counting elements: using an hash and autovivification can quickly provide you the number of elements. The idiom is pretty much as follows:> my @family = <father mother son cat cat dog>;
[father mother son cat cat dog]
> @family.elems
6
> %family-count{ $_ }++ for @family;
Nil
> %family-count.say;
{cat => 2, dog => 1, father => 1, mother => 1, son => 1}
Therefore, asking how many cats live with us? is just a matter of getting a value out of an hash:
> say "There are { %family-count<cat> } cats that live with you";
There are 2 cats that live with you
So far, so good. However, in Raku you have also bags: container that associate to a key and count the number of repetitions. The documentation can be found here.
You can create a new
Bag
or ask an array to baggify itself:
> my $family-bag = @family.Bag;
Bag(cat(2), dog, father, mother, son)
> say "There are { $family-bag<cat> } cats that live with you";
There are 2 cats that live with you
As you can see, the final result is the same. You can even pass a list of repeated items to create the very same bag:
> $family-bag = Bag.new: <cat cat dog mother father son>;
Bag(cat(2), dog, father, mother, son)
Bag
s are immutable and therefore you cannot change the values once the Bag
has been constructed.
You can however use a
BagHash
to modify values:
> $family-bag.^name
Bag
> $family-bag<cat>++;
Cannot resolve caller postfix:<++>(Int:D)
> $family-bag = BagHash.new: <cat cat dog mother son father>;
BagHash(cat(2), dog, father, mother, son)
> $family-bag<cat>++;
2
> $family-bag<cat>;
3
The baggy things have interesting methods to get the number of unique elements (~.elems), of total elements (
.total
) and to get all the element as an array (.roll
) and the keys and values:
> my $family-bag = BagHash.new: <cat cat dog mother son father>;
BagHash(cat(2), dog, father, mother, son)
> $family-bag.roll( $family-bag.total );
(son dog son cat cat mother)
> $family-bag.elems
5
> $family-bag.total
6
> $family-bag.keys
(dog father mother son cat)
> $family-bag.values
(1 1 1 1 2)