Immutable collection of distinct objects with Real weights
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 = (butter => 0.22, sugar => 0.1,flour => 0.275, sugar => 0.02).Mix;say .elems; # OUTPUT: «3»say .keys.sort; # OUTPUT: «butter flour sugar»say .pairs.sort; # OUTPUT: «"butter" => 0.22 "flour" => 0.275 "sugar" => 0.12»say .total; # OUTPUT: «0.615»
Mix
es can be treated as object hashes using the { }
postcircumfix operator, or the < >
postcircumfix operator 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 = (butter => 0.22, sugar => 0.1,flour => 0.275, sugar => 0.02).Mix;say <butter>; # OUTPUT: «0.22»say <sugar>; # OUTPUT: «0.12»say <chocolate>; # OUTPUT: «0»
Mix
objectsMix
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 = mix "a", "a", "b" => 0, 3.14, π, π; # The Pair is a single elementsay .keys.map: *.^name; # OUTPUT: «(Rat Pair Num Str)»say .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 = ("a", "a", "b" => 0, "c" => 3.14).Mix;say .keys.map(); # OUTPUT: «((Str) (Str))»say .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 is Mix = ("a", "a", "b" => 0, "c" => 3.14);say .^name; # OUTPUT: «Mix»say ; # 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 stringsmy = Mix[Str].new: <a b b c c c>;
or using the masquerading syntax:
# only allow stringsmy is Mix[Str] = <a b b c c c>;say <b>; # 2say <d>; # 0# only allow whole numbersmy is Mix[Int] = <a b b c c c>;# Type check failed in binding; expected Int but got Str ("a")
See Operators with set semantics for a complete list of "set operators" applicable to, among other types, Mix
.
Examples:
my = (sugar => ⅓, spice => ¼, all-things-nice => ¾);my = ( sugar => 1, spice => 2);say (<) ; # OUTPUT: «True»say (^) ; # OUTPUT: «Set(all-things-nice)»say (+) ; # OUTPUT: «Bag(spice(2) sugar)»# Unicode versions:say ⊂ ; # OUTPUT: «True»say ⊖ ; # OUTPUT: «Set(all-things-nice)»say ⊎ ; # OUTPUT: «Bag(spice(2) sugar)»
sub mix(* --> Mix)
Creates a new Mix
from @args
.
method Bag (--> Bag)
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 (--> BagHash)
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.
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(Mix: --> 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»
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.