2014-10-10 4 views
2

Я не вижу использования счетчиков. В книге Дейва Томаса указано следующее:Преимущество перечислителей над коллекциями

Перечислитель позволяет вам фиксировать концепцию перечисления как объекта. Это позволяет хранить перечисления в переменных, передавать их как параметры и т. Д.

Но я также могу назначить массивы переменным, передать массивы в качестве аргументов и так далее. На самом деле, я думаю, что с помощью обычного итератора с коллекцией как массив является более кратким, чем при использовании нумератора:

str = "quick brown fox" 
str.scan(/\w+/).each {|w| puts w } 
quick 
brown 
fox 

vs.

str = "quick brown fox" 
enum = str.to_enum(:scan, /\w+/) 
enum.each { |w| puts w } 
quick 
brown 
fox 

версия перечисления требует дополнительного шага и дает тот же результат , Когда более целесообразно использовать перечисление по коллекции с итератором?

ответ

3

Использование Enumerator делает некоторые вещи возможными, что массивы не позволяют.

Перечислитель может представлять последовательность, которая лениво оценивается, то есть код для генерации элемента не запускается до тех пор, пока элемент не понадобится.

Это означает, что Enumerator может представлять бесконечную последовательность. Например:

e = Enumerator.new { |y| s = 'a'; loop { y << s = s.succ } } 
e.first(5) # => ["b", "c", "d", "e", "f"] 

Этот пример показывает бесконечную последовательность, которая подразумевает, что должна быть оценена лениво, потому что ваш компьютер является конечным. Но даже если вы не работаете с бесконечными последовательностями, ленивая оценка все равно может быть очень полезной для экономии времени процессора.

Кроме того, в Enumerator можно использовать внешний итератор, который обеспечивает всевозможную гибкость в том, как вы его используете. (См ответа 7stud для примера.)

+0

Можете ли вы привести пример? – JohnMerlino

+0

@JohnMerino, 'e = [1, 2, 3] .cyclep e.first (10)' – 7stud

2

Перечислителей также внешних итераторов, которая позволяет перебирать два массивов сразу:

e1 = [1, 2, 3].each 
e2 = ['a', 'b', 'c'].each 

loop do 
    num, ch = e1.next, e2.next 
    puts "#{num} -> #{ch}" 
end 

--output:-- 
1 -> a 
2 -> b 
3 -> c 

Когда Enumerator бежит из пунктов, она поднимает Исключение StopIteration и loop() автоматически улавливает это исключение и завершается.

+0

То, что вы здесь делаете, может быть выполнено с помощью массива и целого числа индексов, которое увеличивается, но Enumerator позволяет нам писать его гораздо более лаконично. –

+0

Вау! Итак, это первая причина, по которой я нашел использование 'loop' вместо' while'! –

Смежные вопросы