31 votes

Comment puis-je obtenir un tableau paresseux en Ruby?

Comment puis-je obtenir un tableau paresseux en Ruby ?

En Haskell, je peux parler de [1..], qui est une liste infinie, générée de manière paresseuse au fur et à mesure des besoins. Je peux aussi faire des choses comme iterate (+2) 0, qui applique n'importe quelle fonction que je lui donne pour générer une liste paresseuse. Dans ce cas, cela me donnerait tous les nombres pairs.

Je suis sûr que je peux faire de telles choses en Ruby, mais je n'arrive pas à comprendre comment.

42voto

carlfilips Points 1485

Avec Ruby 1.9, vous pouvez utiliser la classe Enumerator. Voici un exemple tiré de la documentation:

  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]

De plus, voici une astuce intéressante:

  Infinity = 1.0/0

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

Cela ne fonctionne cependant que pour des valeurs consécutives.

23voto

gregolsen Points 630

Récemment Enumerable::Lazy a été ajouté à ruby trunk. Nous le verrons dans ruby 2.0. En particulier:

a = data.lazy.map(&:split).map(&:reverse)

ne sera pas évalué immédiatement.
Le résultat est une instance de Enumerable::Lazy, qui peut être chaînée de manière paresseuse plus loin. Si vous souhaitez obtenir un résultat réel - utilisez #to_a, #take(n) (#take est maintenant paresseux aussi, utilisez #to_a ou #force), etc.
Si vous voulez en savoir plus sur ce sujet et sur mon patch C - consultez mon article de blog Ruby 2.0 Enumerable::Lazy

6voto

banister Points 13181

Gamme paresseuse (nombres naturels):

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

Gamme paresseuse (nombres pairs):

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

Notez que vous pouvez également étendre Enumerable avec quelques méthodes pour faciliter le travail avec les plages paresseuses (et ainsi de suite):

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

# premiers 4 nombres pairs
(1..Inf).lazy_select { |v| v.even? }.take(4)

sortie:
[2, 4, 6, 8]

Plus d'informations ici: http://banisterfiend.wordpress.com/2009/10/02/wtf-infinite-ranges-in-ruby/

Il existe également des implémentations de lazy_map et lazy_select pour la classe Enumerator qui peuvent être trouvées ici: http://www.michaelharrison.ws/weblog/?p=163

4voto

Mr. Black Points 2342

En Ruby 2.0.0, une nouvelle méthode "Lazy" a été introduite dans la classe Enumerable.

Vous pouvez vérifier le cœur et l'utilisation de la fonction lazy ici..

http://www.ruby-doc.org/core-2.0/Enumerator/Lazy.html
https://github.com/yhara/enumerable-lazy
http://shugomaeda.blogspot.in/2012/03/enumerablelazy-and-its-benefits.html

2voto

Je suis surpris que personne n'ait encore répondu correctement à cette question

Alors, récemment j'ai trouvé cette méthode Enumerator.produce qui, en conjonction avec .lazy, fait exactement ce que vous avez décrit mais à la manière de Ruby

Exemples

Enumerator.produce(0) do  
   _1 + 2
end.lazy
  .map(&:to_r) 
  .take(1_000)
  .inject(&:+)
# => (999000/1)

def fact(n)
  = Enumerator.produce(1) do  
    _1 + 1
  end.lazy
  .take(n)
  .inject(&:*)

fact 6 # => 720

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X