class Mix
class Mix does Mixy { }
A Mix
is an immutable collection of distinct elements
in no particular order that each have a real-number weight assigned to
them. (For mutable mixes, see MixHash instead.)
Mix
es are often used for performing weighted random selections - see
.roll.
Objects/values of any type are allowed as mix elements. Within a Mix
,
items that would compare positively with the === operator are
considered the same element, with a combined weight.
my $recipe = (butter => 0.22, sugar => 0.1,
flour => 0.275, sugar => 0.02).Mix;
say $recipe.elems; # OUTPUT: «3»
say $recipe.keys.sort; # OUTPUT: «butter flour sugar»
say $recipe.pairs.sort; # OUTPUT: «"butter" => 0.22 "flour" => 0.275 "sugar" => 0.12»
say $recipe.total; # OUTPUT: «0.615»
Mix
es can be treated as object hashes using the
{ } postcircumfix operator,
or the
< > postcircumfix operator|/language/operators#postcircumfix_<_>
for literal string keys, which
returns the corresponding numeric weight for keys that
are elements of the mix, and 0
for keys that aren't:
my $recipe = (butter => 0.22, sugar => 0.1,
flour => 0.275, sugar => 0.02).Mix;
say $recipe<butter>; # OUTPUT: «0.22»
say $recipe<sugar>; # OUTPUT: «0.12»
say $recipe<chocolate>; # OUTPUT: «0»
Creating Mix
objects
Mix
es can be composed using the mix subroutine (or
Mix.new
, for which it is a shorthand). Any positional parameters,
regardless of their type, become elements of the mix - with a weight of
1
for each time the parameter occurred:
my $n = mix "a", "a", "b" => 0, 3.14, π, π; # The Pair is a single element
say $n.keys.map: *.^name; # OUTPUT: «(Rat Pair Num Str)»
say $n.pairs;
# OUTPUT: «(3.14 => 1 (b => 0) => 1 3.141592653589793 => 2 a => 2)»
Alternatively, the .Mix
coercer (or its functional form, Mix()
)
can be called on an existing object to coerce it to a Mix
. Its
semantics depend on the type and contents of the object. In general it
evaluates the object in list context and creates a mix with the
resulting items as elements, although for Hash-like objects or Pair
items, only the keys become elements of the mix, and the (cumulative)
values become the associated numeric weights:
my $n = ("a", "a", "b" => 0, "c" => 3.14).Mix;
say $n.keys.map(&WHAT); # OUTPUT: «((Str) (Str))»
say $n.pairs; # OUTPUT: «(a => 2 c => 3.14)»
Elements with a 0 value, as b
above, are simply eliminated from the Mix
.
Alternatively, since Mix
es are Associative, we can use the %
sigil to
declare them; in that case, we can employ is
to declare their type:
my %n is Mix = ("a", "a", "b" => 0, "c" => 3.14);
say %n.^name; # OUTPUT: «Mix»
say %n; # OUTPUT: «Mix(a(2) c(3.14))»
Since 6.d (2019.03 and later) it is also possible to specify the type of values
you would like to allow in a Mix
. This can either be done when calling
.new
:
# only allow strings
my $n = Mix[Str].new: <a b b c c c>;
or using the masquerading syntax:
# only allow strings
my %m is Mix[Str] = <a b b c c c>;
say %m<b>; # OUTPUT: «2»
say %m<d>; # OUTPUT: «0»
# only allow whole numbers
my %m is Mix[Int] = <a b b c c c>;
# Type check failed in binding; expected Int but got Str ("a")
Operators
See Operators with set
semantics for a complete
list of "set operators" applicable to, among other types, Mix
.
Examples:
my $this-mix = (sugar => ⅓, spice => ¼, all-things-nice => ¾);
my $that-mix = ( sugar => 1, spice => 2);
say $that-mix (<) $this-mix; # OUTPUT: «True»
say $that-mix (^) $this-mix; # OUTPUT: «Set(all-things-nice)»
say $that-mix (+) $this-mix; # OUTPUT: «Bag(spice(2) sugar)»
# Unicode versions:
say $that-mix ⊂ $this-mix; # OUTPUT: «True»
say $that-mix ⊖ $this-mix; # OUTPUT: «Set(all-things-nice)»
say $that-mix ⊎ $this-mix; # OUTPUT: «Bag(spice(2) sugar)»
sub mix
sub mix(*@args --> Mix)
Creates a new Mix
from @args
.
Methods
method Bag
method Bag (--> Bag:D)
Coerces the Mix
to a Bag. The weights are convert to
Int, which means the number of keys in the resulting
Bag can be fewer than in the original Mix
, if any of the weights
are negative or truncate to zero.
method BagHash
method BagHash (--> BagHash:D)
Coerces the Mix
to a BagHash. The weights are
convert to Int, which means the number of keys in the
resulting BagHash can be fewer than in the original Mix
, if any of
the weights are negative or truncate to zero.
method reverse
Note: This method is inherited from Any,
however, Mix
es do not have an inherent order and you should not trust
it returning a consistent output.
method total
method total(Mix:D: --> Real)
Returns the sum of all the weights
say mix('a', 'b', 'c', 'a', 'a', 'd').total == 6; # OUTPUT: «True»
say %(a => 5.6, b => 2.4).Mix.total == 8; # OUTPUT: «True»
Note on order
Same as the other elements in the Bag/Mix suite,
order is not guaranteed or consistent and you shouldn't rely on methods
like reverse
above returning always the same result.