Как я могу получить ленивый массив в Ruby?

Как я могу получить ленивый массив в Ruby?

В Haskell я могу говорить о [1..], который является бесконечным списком, лениво сгенерированным по мере необходимости. Я могу также сделать вещи как iterate (+2) 0, который применяет любую функцию, я даю ее для генерации ленивого списка. В этом случае это дало бы мне все четные числа.

Я уверен, что могу сделать такие вещи в Ruby, но, может казаться, не удаюсь как.

30
задан the Tin Man 11 September 2013 в 19:07
поделиться

4 ответа

В Ruby 1.9 вы можете использовать класс Enumerator. Вот пример из документации:

  fib = Enumerator.new { |y|
    a = b = 1
    loop {
      y << a
      a, b = b, a + b
    }
  }

  p fib.take(10) #=> [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

Также вот неплохой трюк:

  Infinity = 1.0/0

  range = 5..Infinity
  p range.take(10) #=> [5, 6, 7, 8, 9, 10, 11, 12, 13, 14]

Правда, он работает только для последовательных значений.

41
ответ дан 27 November 2019 в 23:27
поделиться

Ленивый диапазон (натуральные числа):

Inf = 1.0/0.0
(1..Inf).take(3) #=> [1, 2, 3]

Ленивый диапазон (четные числа):

(0..Inf).step(2).take(5) #=> [0, 2, 4, 6, 8]

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

module Enumerable
  def lazy_select
    Enumerator.new do |yielder|
      each do |obj|
        yielder.yield(obj) if yield(obj)
      end
    end
  end
end

# first 4 even numbers
(1..Inf).lazy_select { |v| v.even? }.take(4)

output:
[2, 4, 6, 8]

Больше информации здесь: http://banisterfiend.wordpress.com/2009/10/02/wtf-infinite-ranges-in-ruby/

Существуют также реализации lazy_map и lazy_select для класса Enumeratorкоторые можно найти здесь: http://www.michaelharrison.ws/weblog/?p=163

6
ответ дан 27 November 2019 в 23:27
поделиться

Как я уже сказал в своих комментариях, реализация такой вещи, как ленивые массивы, не будет разумной.

Использование Enumerable вместо этого может хорошо работать в некоторых ситуациях, но отличается от ленивых списков в некоторых моментах: такие методы как map и filter не будут лениво оцениваться (поэтому они не будут работать на бесконечных перечислителях), а элементы, которые были вычислены один раз, не сохраняются, поэтому если вы обращаетесь к элементу дважды, он будет вычислен дважды.

Если вы хотите получить точное поведение ленивых списков haskell в ruby, существует lazylist gem, который реализует ленивые списки.

1
ответ дан 27 November 2019 в 23:27
поделиться

Массивы Ruby динамически расширяются по мере необходимости. Вы можете применять к ним блоки, чтобы возвращать такие вещи, как четные числа.

array = []
array.size # => 0
array[0] # => nil
array[9999] # => nil
array << 1
array.size # => 1
array << 2 << 3 << 4
array.size # => 4

array = (0..9).to_a
array.select do |e|
  e % 2 == 0
end

# => [0,2,4,6,8]

Это поможет?

-3
ответ дан 27 November 2019 в 23:27
поделиться
Другие вопросы по тегам:

Похожие вопросы: