One of the most commonly used Enumerables happens to be one you might have
already seen - count
.
When dealing with Array
s, we can use count
to find the total number of
elements in the array.
[1, 2, 3].count # => 3
You may have noticed in some previous examples, instead of count
, we might
have used length
.
[1, 2, 3].length # => 3
In fact, there is a third alias, size
, that also works:
[1, 2, 3].size # => 3
For this sort of task - "reducing" an entire array of data down to a single value - the three terms are interchangeable.
However, count
has additional functionality that length
and size
do not
have. count
is an Enumerable.
In this lesson, we're going to take a more in-depth look at count
, why it is
different than length
and size
, and how it is useful. At the end, you will
be tasked with writing your own
length
and size
are both built-in methods for Array
s that serve a single
task - get the pre-computed total number of elements in a given array. That
is all they do (though we've seen working with while
loops that this alone can
be pretty useful). Array
s always keep track of their size, and these methods
access that information.
As we mentioned, count
is an Enumerable. Enumerables are available to all
Array
s, but operate a bit differently - they always enumerate; they move
over elements in a collection one by one. count
doesn't just ask an Array
for
information it already knows. It counts every element.
Because count
goes through the work of enumerating over each element, we have
some additional control over how it counts. We can do this by passing a
block to count
.
[1, 2, 3,].count do |element|
# code in here runs every time count enumerates over an element
# that element is available as the name we define inside the pipes above
end
A block in Ruby refers to code inside do...end
or curly braces {}
. We've
seen them before with while
loops. The code stored inside will run every time
the block is called. In this case, the code will run for every element in the
array count
is called from. We can access the current element as whatever name
we define inside the pipes after do
. In this case, we used element
, but we
could choose whatever name we'd like.
In the block, we include code that will determine whether or not to count the current element. For instance, in an array of integers, maybe we only want to count elements that are even:
[1, 2, 3, 4].count do |element|
element.even?
end
count
will count every time the block returns a truthy value. In the case
above, count
is checking if each element is even, going through the array
elements like so:
1.even? # => false
2.even? # => true
3.even? # => false
4.even? # => true
Since two expressions evaluate to true
, count
returns 2
as
the result.
If you recall, we implemented code for counting even values in an earlier
lesson. Back then, we used while
loops and wrote something similar to the
following:
total = 0
array = [1, 2, 3, 4]
index = 0
while index < array.length do
if array[index].even?
total += 1 # total is only incremented when the current array element is even
end
index += 1
end
total
count
provides a streamlined way to accomplish this task. Let's consider
another example. Imagine we had an array of numbers, and we only wanted to count
those that are positive.
array = [0, 1, -9, 24, 5, -10]
Using a while
loop, we could modify the conditional statement to check if each
element is greater than zero.
...
if array[index] > 0
total += 1 # only increments when teh current element is greater than zero
end
...
Using count
and a block, we do the same:
array.count do |num|
num > 0
end
# => 3
If we wanted to use the curly brace syntax instead:
array.count { |num| num > 0 }
# => 3
Both forms are valid, though Rubyists tend to use do..end
for readability if
there are multiple lines of code in the block.
It's time to practice what we've learned. For this lab, your task is to
implement two methods using count
. Complete your work in lib/array_count.rb
and run learn
to check your code.
The count_strings
method takes in an array of different data types, enumerates
over them and returns the total number of String
s present in the array. For
example, if we had the following array:
array = [1, "hello", [], 5.01, "world", :name, { a: 1 }]
Passed into count_strings
, we should get 2
in return.
count_strings(array)
# => 2
The count_empty_strings
method is a slight variation on the last method - it
takes in an array of different data types and returns the total number of
empty String
s present. For example, if we had the
following array:
array = [ "", "Hello", 4, [], "", "" ]
Passed into count_empty_strings
, we should get 3
in return.
count_empty_strings(array)
# => 3
The count
Enumerable is handy way to count things in a specific way. Unlike
the length
and size
array methods, count
enumerates over every element in
a collection. Because it enumerates, we can use a block to customize
what count
considers worthy of counting.
We will soon see that all the Enumerables we learn about will use a block this way. They all have the ability to step through a collection. At every step, they yield some control to us via a block.