Enumeration refers to traversing, searching, filtering, and querying objects.

In Crystal, we have classes like `Array`

, `Hash`

, `Range`

, etc. which get their enumeration features by including the Enumerable module.

This `Enumerable`

module provides various methods e.g., `#select`

, `#map`

, `#reduce`

, and `#uniq`

which we frequently use, and less known `#tally`

about which this post is.

`#tally`

counts the number of occurrences of an element in a collection and returns a hash containing the count for all elements.

```
['a', 'b', 'c', 'b'].tally # => {'a'=>1, 'b'=>2, 'c'=>1}
```

## Example

Consider the example of a list of words, and you want to count the total number of each char.

This type of problem is a perfect candidate to leverage our `#tally`

method to calculate the total quantity of chars.

Consider you have words as follows:

```
word_one = "crystal"
word_two = "ruby"
```

## Before

Calculating the quantity of chars in each word:

```
tally_one = word_one.chars.tally
# => {'c' => 1, 'r' => 1, 'y' => 1, 's' => 1, 't' => 1, 'a' => 1, 'l' => 1}
tally_two = word_two.chars.tally
# => {'r' => 1, 'u' => 1, 'b' => 1, 'y' => 1}
total_tally = tally_one.merge(tally_two) { |k, v1, v2| v1 + v2 }
# => {'c' => 1, 'r' => 2, 'y' => 2, 's' => 1, 't' => 1, 'a' => 1, 'l' => 1, 'u' => 1, 'b' => 1}
```

We have merged `tally_one`

and `tally_two`

and summed hash values to get the combined count of the chars.

## After

To calculate the total, Crystal 1.4 `Enumerable#tally`

now accepts an optional hash to count occurrences.

In this case, we can store the running tally of the number of items and pass it to the `#tally`

method.

```
word_one = "crystal"
word_two = "ruby"
total_tally = {} of Char => Int32
word_one.chars.tally(total_tally)
word_two.chars.tally(total_tally)
total_tally
=> {'c' => 1, 'r' => 2, 'y' => 2, 's' => 1, 't' => 1, 'a' => 1, 'l' => 1, 'u' => 1, 'b' => 1}
```

As you can see in the above example in Crystal 1.4, we have passed the `total_tally`

hash as an argument to the `#tally`

method that stores the count of chars.

Finally, we can simplify the code to one line:

```
words = ["crystal", "ruby"]
total_tally = words.reduce({} of Char => Int32) { |acc, word| word.chars.tally(acc) }
```

## Top comments (0)