Why doesn't Enumerable have a length attribute in Ruby?

At least in Ruby 1.9.3, Enumerable objects do not have a length attribute.

As far as I can tell, all that Enumerable is a set is, as evidenced by methods such as sort and find_index .

A set always has a well-defined length (... right?), So why not this property?

+7
source share
3 answers

Enumerable has a count method, which is usually the intuitive "length" of an enumeration.

But why not call it "length"? Well, because it works in a completely different way. In Ruby, embedded data structures such as Array and Hash , length simply retrieve the pre-calculated size of the data structure. He must always return instantly.

For Enumerable#count , however, there is no way to find out what structure it is working on, and therefore there is no quick and smart way to get the size of an enumeration (this is because Enumerable is a module and can be included in it). in any class). The only way to get the size of the transfer is to actually list it and take it as you go. For endless enumerations, count will (accordingly) loop forever and never return.

+11
source

Enumerations are not guaranteed length - the only requirement for an object with which Enumerable will enumerate is that it responds with #each , which forces it to return the next element in the series and #<=> #each , which allows you to compare the values ​​provided by an enumerable. Methods like #sort will list the entire collection during sorting, but may not know the boundaries of the set in advance. Consider:

 class RandomSizeEnumerable include Enumerable def each value = rand 1000 while value != 500 yield value value = rand 1000 end end # Not needed for this example, but included as a part of the Enumerable "interface". # You only need this method if #max, #min, or #sort are used on this class. def <=>(a, b) a <=> b end end 

This enumeration will be called until the iterator produces the value "500", which will lead to its reinstallation. The result set is collected and sorted. However, the #length method #length not make sense in this context, since the length is #length until the iterator is exhausted!

We can call #length as a result of things like #sort , since they return an array:

 p RandomSizeEnumerable.new.sort.length # 321 p RandomSizeEnumerable.new.sort.length # 227 p RandomSizeEnumerable.new.sort.length # 299 

#length is usually used when the length is known and can be returned in constant time, while #count (and sometimes #size ) is usually used when the length can be unknown in advance and needs to be calculated by repeating a set of results (thus taking linear time). If you need the size of the result set provided by Enumerable, try using .to_a.length #count .

+2
source

Enumerable is not a class, but a module - a collection of cross-cutting functions that are used by several classes.

For example, Array , Set and Hash all include this - you can call them any of the Enumerable methods.

Enumerable is noteworthy in that it requires very little host class. All you have to do is define each and include Enumerable method, and you will get all these methods for free! Example:

 class CountUntil def initialize(number) @number = number end include Enumerable def each current = 0 while current < @number yield current current += 1 end end end # Usage: CountUntil.new(10).map { |n| n * 5 } # => [0, 5, 10, 15, 20, 25, 30, 35, 40, 45] 

As you can see, I never defined a CountUntil#map , but I got it for free from Enumerable .

To ask a question about length : not all classes containing Enumerable have a specific length, although most do. For example, Enumerator can be used to create endless streams.

0
source

Source: https://habr.com/ru/post/983273/


All Articles