txt: ## baghash.md
  class BagHash
  
  Mutable collection of distinct objects with integer weights
  
  ```raku
  class BagHash does Baggy { }
  ```
  
  A `BagHash` is a mutable bag/multiset, meaning a collection of distinct items in no particular order that each have an integer weight assigned to them signifying how many copies of that element are considered "in the bag". If you do not need the mutability that a `BagHash` provides, consider using the *immutable* [`Bag`](/type/Bag) type instead.
  
  An item may be a definite object of any type – not just a [`Str`](/type/Str). For example, you can store [`Sub`](/type/Sub)'s in a `BagHash`, and you will store the actual [`Sub`](/type/Sub) rather than a string with the same name as the [`Sub`](/type/Sub). Within a `BagHash`, items that would compare positively with the [===](/routine/===) operator are considered the same element, with the number of how many there were as its weight. Alternatively, you can use the `kxxv` method to easily get back the expanded list of items (without the order):
  
  ```raku
  my $breakfast = <spam eggs spam spam bacon spam>.BagHash;
  
  say $breakfast.elems;      # OUTPUT: «3␤»
  say $breakfast.keys.sort;  # OUTPUT: «bacon eggs spam␤»
  
  say $breakfast.total;      # OUTPUT: «6␤»
  say $breakfast.kxxv.sort;  # OUTPUT: «bacon eggs spam spam spam spam␤»
  
  ```
  
  `BagHash`es can be treated as object hashes using the [`{ }` postcircumfix operator](/language/operators#postcircumfix_{_}), or the [`< >` postcircumfix operator](/language/operators#postcircumfix_<_>) for literal string keys, which returns the corresponding integer weight for keys that are elements of the bag, and `0` for keys that aren't. These operators can also be used to modify weights (see [Updating BagHash Objects](#Updating_BagHash_Objects), below).
  
  ```raku
  my $breakfast = <spam eggs spam spam bacon spam>.BagHash;
  say $breakfast<bacon>;     # OUTPUT: «1␤»
  say $breakfast<spam>;      # OUTPUT: «4␤»
  say $breakfast<sausage>;   # OUTPUT: «0␤»
  
  $breakfast<sausage> = 2;
  $breakfast<bacon>--;
  say $breakfast.kxxv.sort;  # OUTPUT: «eggs sausage sausage spam spam spam spam␤»
  
  ```
  
  # [Creating `BagHash` objects](#class_BagHash "go to top of document")[§](#Creating_BagHash_objects "direct link")
  
  `BagHash`es can be composed using `BagHash.new`. Any positional parameters, regardless of their type, become elements of the bag:
  
  ```raku
  my $n = BagHash.new: "a", "b", "c", "c";
  say $n.raku;             # OUTPUT: «("b"=>1,"a"=>1,"c"=>2).BagHash␤»
  say $n.keys.raku;        # OUTPUT: «("b", "a", "c").Seq␤»
  say $n.values.raku;      # OUTPUT: «(1, 1, 2).Seq␤»
  ```
  
  Besides, `BagHash.new-from-pairs` can create a `BagHash` with items and their occurrences.
  
  ```raku
  my $n = BagHash.new-from-pairs: "a" => 0, "b" => 1, "c" => 2, "c" => 2;
  say $n.raku;             # OUTPUT: «("b"=>1,"c"=>4).BagHash␤»
  say $n.keys.raku;        # OUTPUT: «("b", "c").Seq␤»
  say $n.values.raku;      # OUTPUT: «(1, 4).Seq␤»
  ```
  
  Alternatively, the `.BagHash` coercer (or its functional form, `BagHash()`) can be called on an existing object to coerce it to a `BagHash`. Its semantics depend on the type and contents of the object. In general it evaluates the object in list context and creates a bag with the resulting items as elements, although for Hash-like objects or Pair items, only the keys become elements of the bag, and the (cumulative) values become the associated integer weights:
  
  ```raku
  my $m = ("a", "b", "c", "c").BagHash;
  my $n = ("a" => 0, "b" => 1, "c" => 2, "c" => 2).BagHash;
  say $m.raku;             # OUTPUT: «("b"=>1,"a"=>1,"c"=>2).BagHash␤»
  say $n.raku;             # OUTPUT: «("b"=>1,"c"=>4).BagHash␤»
  ```
  
  You can also create `BagHash` masquerading as a hash by using the `is` trait:
  
  ```raku
  my %bh is BagHash = <a b b c c c>;
  say %bh<b>;  # OUTPUT: «2␤»
  say %bh<d>;  # OUTPUT: «0␤»
  ```
  
  Since 6.d (2019.03 and later) it is also possible to specify the type of values you would like to allow in a `BagHash`. This can either be done when calling `.new`:
  
  ```raku
  # only allow strings
  my $n = BagHash[Str].new: <a b b c c c>;
  ```
  
  or using the masquerading syntax:
  
  ```raku
  # only allow strings
  my %bh is BagHash[Str] = <a b b c c c>;
  say %bh<b>;  # OUTPUT: «2␤»
  say %bh<d>;  # OUTPUT: «0␤»
  
  # only allow whole numbers
  my %bh is BagHash[Int] = <a b b c c c>;
  # Type check failed in binding; expected Int but got Str ("a")
  ```
  
  # [Updating BagHash Objects](#class_BagHash "go to top of document")[§](#Updating_BagHash_Objects "direct link")
  
  Once you have created a `BagHash`, you can update its values in two ways. First, you can use the `add` and `remove` methods:
  
  ```raku
  my $n = BagHash.new: "a", "b", "c", "c";
  say $n.raku;             # OUTPUT: «("b"=>1,"a"=>1,"c"=>2).BagHash␤»
  $n.add('c');
  say $n.raku;             # OUTPUT: «("b"=>1,"c"=>3,"a"=>1).BagHash␤»
  $n.remove(('b', 'a'),);
  say $n.raku;             # OUTPUT: «("c"=>3).BagHash␤»
  $n.remove('c');
  say $n.raku;             # OUTPUT: «("c"=>2).BagHash␤»
  ```
  
  Note that, as shown in the final example, the `remove` method removes a *single* value from the `BagHash`; it doesn't entirely remove the key from the `BagHash`.
  
  Alternatively, you can use assignment (including with [autoincrement operators](/language/operators#Autoincrement_precedence) such as `++` and `--`) to modify the `BagHash`'s contents.
  
  ```raku
  my $n = BagHash.new: "a", "b", "c", "c";
  say $n.raku;             # OUTPUT: «("b"=>1,"a"=>1,"c"=>2).BagHash␤»
  $n<c>++;
  say $n.raku;             # OUTPUT: «("b"=>1,"c"=>3,"a"=>1).BagHash␤»
  $n<b> -= 1;
  say $n.raku;             # OUTPUT: «("a"=>1,"c"=>3).BagHash␤»
  $n{'a'} = 0;
  say $n.raku;             # OUTPUT: «("c"=>3).BagHash␤»
  ```
  
  Using either syntax, if you set the value of an item to zero or less than zero, the item will be removed from the `BagHash`.
  
  # [Operators](#class_BagHash "go to top of document")[§](#Operators "direct link")
  
  See [Operators with set semantics](/language/setbagmix#Operators_with_set_semantics) for a complete list of "set operators" applicable to, among other types, `BagHash`.
  
  Examples:
  
  ```raku
  my ($a, $b) = BagHash.new(2, 2, 4), BagHash.new(2, 3, 3, 4);
  
  say $a (<) $b;   # OUTPUT: «False␤»
  say $a (<=) $b;  # OUTPUT: «False␤»
  say $a (^) $b;   # OUTPUT: «BagHash(3(2) 2)␤»
  say $a (+) $b;   # OUTPUT: «BagHash(2(3) 4(2) 3(2))␤»
  
  # Unicode versions:
  say $a ⊂ $b;  # OUTPUT: «False␤»
  say $a ⊆ $b;  # OUTPUT: «False␤»
  say $a ⊖ $b;  # OUTPUT: «BagHash(3(2) 2)␤»
  say $a ⊎ $b;  # OUTPUT: «BagHash(2(3) 4(2) 3(2))␤»
  
  ```
  
  # [Note on `reverse` and ordering.](#class_BagHash "go to top of document")[§](#Note_on_reverse_and_ordering. "direct link")
  
  BagHash inherits `reverse` from [Any](/type/Any#routine_reverse), however, [`Bag`](/type/Bag)s do not have an inherent order and you should not trust it returning a consistent output.
  
  If you sort a BagHash, the result is a list of pairs, at which point `reverse` makes perfect sense:
  
  ```raku
  my $a = BagHash.new(2, 2, 18, 3, 4);
  say $a;  # OUTPUT: «BagHash(18 2(2) 3 4)␤»
  
  say $a.sort;  # OUTPUT: «(2 => 2 3 => 1 4 => 1 18 => 1)␤»
  say $a.sort.reverse;  # OUTPUT: «(18 => 1 4 => 1 3 => 1 2 => 2)␤»
  
  ```
  
  ## [method add](#class_BagHash "go to top of document")[§](#method_add "direct link")
  
  ```raku
  method add(BagHash: \to-add, *%_ --> Nil)
  ```
  
  When `to-add` is a single item, `add` inserts it into the `BagHash` or, if it was already present, increases its weight by 1. When `to-add` is a [`List`](/type/List), [`Array`](/type/Array), [`Seq`](/type/Seq), or any other type that `does` the [`Iterator`](/type/Iterator) Role, `add` inserts each element of the [`Iterator`](/type/Iterator) into the [`SetHash`](/type/SetHash) or increments the weight of each element by 1.
  
  *Note:* Added in version 2020.02.
  
  ## [method remove](#class_BagHash "go to top of document")[§](#method_remove "direct link")
  
  ```raku
  method remove(BagHash: \to-remove, *%_ --> Nil)
  ```
  
  When `to-remove` is a single item, `remove` reduces the weight of that item by one. If this results in the item having a weight of 0, this removes the item from the `BagHash`. If the item is not present in the `BagHash`, `remove` has no effect. When `to-remove` is a [`List`](/type/List), [`Array`](/type/Array), [`Seq`](/type/Seq), or any other type that `does` the [`Iterator`](/type/Iterator) Role, `remove` reduces the weight of each element by 1 and removes any items with the resulting weight of 0.
  
  *Note:* Added in version 2020.02.
  
  # [See Also](#class_BagHash "go to top of document")[§](#See_Also "direct link")
  
  [Sets, Bags, and Mixes](/language/setbagmix)
  
  # [Typegraph](# "go to top of document")[§](#typegraphrelations "direct link")
  
  Type relations for `BagHash`
  
  
  
  raku-type-graph
  
  
  
  BagHash
  BagHash
  
  
  Any
  Any
  
  
  BagHash->Any
  
  
  
  Baggy
  Baggy
  
  
  BagHash->Baggy
  
  
  
  Mu
  Mu
  
  
  Any->Mu
  
  
  
  Associative
  Associative
  
  
  QuantHash
  QuantHash
  
  
  QuantHash->Associative
  
  
  
  Baggy->QuantHash
  
  [Expand chart above](/assets/typegraphs/BagHash.svg)
  