Как пакетно перечислить в ruby - PullRequest
0 голосов
/ 10 января 2020

В моем стремлении понять ruby enumerable, у меня есть нечто похожее на следующее

FileReader.read(very_big_file)
          .lazy
          .flat_map {|line| get_array_of_similar_words } # array.size is ~10
          .each_slice(100) # wait for 100 items
          .map{|array| process_100_items}

Столько, сколько каждый вызов flat_map испускает массив из ~ 10 элементов, я ожидал вызова each_slice для пакетирования элементов в сотнях, но это не так. Т.е. подождите, пока не будет 100 элементов, прежде чем передать их на последний .map вызов.

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

1 Ответ

2 голосов
/ 10 января 2020

Чтобы увидеть, как lazy влияет на вычисления, давайте рассмотрим пример. Сначала создайте файл:

str =<<~_
Now is the
time for all
good Ruby coders
to come to
the aid of
their bowling
team
_

fname = 't' 
File.write(fname, str)
  #=> 82

и укажите размер среза:

slice_size = 4

Теперь я буду читать строки, одну за другой, разбивать строки на слова, удалять повторяющиеся слова а затем добавить эти слова в массив. Как только массив содержит как минимум 4 слова, я возьму первые четыре и сопоставлю их с самым длинным словом из 4. Далее следует код. Чтобы показать, как продвигаются вычисления, я добавлю код к операторам puts. Обратите внимание, что IO :: foreach без блока возвращает перечислитель.

IO.foreach(fname).
   lazy.
   tap { |o| puts "o1 = #{o}" }.
   flat_map { |line|
     puts "line = #{line}"
     puts "line.split.uniq = #{line.split.uniq} "
     line.split.uniq }.
   tap { |o| puts "o2 = #{o}" }.
   each_slice(slice_size).
   tap { |o| puts "o3 = #{o}" }.
   map { |arr|
     puts "arr = #{arr}, arr.max = #{arr.max_by(&:size)}"
     arr.max_by(&:size) }.
   tap { |o| puts "o3 = #{o}" }.
   to_a
  #=> ["time", "good", "coders", "bowling", "team"] 

Отображается следующее:

o1 = #<Enumerator::Lazy:0x00005992b1ab6970>
o2 = #<Enumerator::Lazy:0x00005992b1ab6880>
o3 = #<Enumerator::Lazy:0x00005992b1ab6678>
o3 = #<Enumerator::Lazy:0x00005992b1ab6420>
line = Now is the
line.split.uniq = ["Now", "is", "the"] 
line = time for all
line.split.uniq = ["time", "for", "all"] 
arr = ["Now", "is", "the", "time"], arr.max = time
line = good Ruby coders
line.split.uniq = ["good", "Ruby", "coders"] 
arr = ["for", "all", "good", "Ruby"], arr.max = good
line = to come to
line.split.uniq = ["to", "come"] 
line = the aid of
line.split.uniq = ["the", "aid", "of"] 
arr = ["coders", "to", "come", "the"], arr.max = coders
line = their bowling
line.split.uniq = ["their", "bowling"] 
arr = ["aid", "of", "their", "bowling"], arr.max = bowling
line = team
line.split.uniq = ["team"] 
arr = ["team"], arr.max = team

Если строка lazy. удалена возвращаемое значение такое же, но отображается следующее (.to_a в конце теперь излишне):

o1 = #<Enumerator:0x00005992b1a438f8>
line = Now is the
line.split.uniq = ["Now", "is", "the"] 
line = time for all
line.split.uniq = ["time", "for", "all"] 
line = good Ruby coders
line.split.uniq = ["good", "Ruby", "coders"] 
line = to come to
line.split.uniq = ["to", "come"] 
line = the aid of
line.split.uniq = ["the", "aid", "of"] 
line = their bowling
line.split.uniq = ["their", "bowling"] 
line = team
line.split.uniq = ["team"] 
o2 = ["Now", "is", "the", "time", "for", "all", "good", "Ruby",
      "coders", "to", "come", "the", "aid", "of", "their",
      "bowling", "team"]
o3 = #<Enumerator:0x00005992b1a41a08>
arr = ["Now", "is", "the", "time"], arr.max = time
arr = ["for", "all", "good", "Ruby"], arr.max = good
arr = ["coders", "to", "come", "the"], arr.max = coders
arr = ["aid", "of", "their", "bowling"], arr.max = bowling
arr = ["team"], arr.max = team
o3 = ["time", "good", "coders", "bowling", "team"]
...