How can I get a lazy array in Ruby?
如何在Ruby中获得一个惰性数组?
In Haskell, I can talk about [1..]
, which is an infinite list, lazily generated as needed. I can also do things like iterate (+2) 0
, which applies whatever function I give it to generate a lazy list. In this case, it would give me all even numbers.
在Haskell,我可以谈论[1..它是一个无限的列表,根据需要缓慢地生成。我还可以做一些事情,比如iterate(+2) 0,它应用我给它的任何函数来生成一个惰性列表。在这种情况下,它会给我所有的偶数。
I'm sure I can do such things in Ruby, but can't seem to work out how.
我确信我可以在Ruby中做这样的事情,但似乎不知道如何去做。
7 个解决方案
#1
40
With Ruby 1.9 you can use the Enumerator class. This is an example from the docs:
使用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]
Also, this is a nice trick:
另外,这是一个很好的技巧:
Infinity = 1.0/0
range = 5..Infinity
p range.take(10) #=> [5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
This one only works for consecutive values though.
但是这个只适用于连续的值。
#2
20
Recently Enumerable::Lazy has been added to ruby trunk. We'll see it in ruby 2.0. In particular:
最近可枚举的::Lazy已添加到ruby主干中。我们将在ruby 2.0中看到它。特别是:
a = data.lazy.map(&:split).map(&:reverse)
will not be evaluated immediately.
The result is instance of Enumerable::Lazy, that can be lazy chained any further. If you want to get an actual result - use #to_a
, (#take(n)
#take
is now lazy too, use #to_a
or #force
), etc.
If you want more on this topic and my C patch - see my blog post Ruby 2.0 Enumerable::Lazy
不会立即进行评估。结果是Enumerable:::Lazy,它可以被惰性链接得更远。如果你想要得到一个真实的结果——使用#to_a, #take(n) (#take现在也是懒惰的,使用#to_a或#force)等等
#3
6
Lazy range (natural numbers):
懒惰的范围(自然数):
Inf = 1.0/0.0
(1..Inf).take(3) #=> [1, 2, 3]
Lazy range (even numbers):
懒惰的范围(偶数):
(0..Inf).step(2).take(5) #=> [0, 2, 4, 6, 8]
Note, you can also extend Enumerable
with some methods to make working with lazy ranges (and so on) more convenient:
注意,您还可以使用一些方法扩展Enumerable,以便使用lazy ranges(等等)更加方便:
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]
More info here: http://banisterfiend.wordpress.com/2009/10/02/wtf-infinite-ranges-in-ruby/
更多信息:http://banisterfiend.wordpress.com/2009/10/02/wtf-infinite-ranges-in-ruby/
There are also implementations of lazy_map, and lazy_select for the Enumerator
class that can be found here: http://www.michaelharrison.ws/weblog/?p=163
也有lazy_map和lazy_select的实现,用于可以在这里找到的Enumeratorclass: http://www.michaelharrison.ws/weblog/?
#4
4
In Ruby 2.0.0, they were introduced new method "Lazy" in Enumerable class.
在Ruby 2.0.0中,在可枚举类中引入了新的方法“Lazy”。
You can check the lazy function core and usage here..
您可以在这里查看惰性函数核心和用法。
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
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
#5
1
As I already said in my comments, implementing such a thing as lazy arrays wouldn't be sensible.
正如我在评论中已经说过的,实现诸如惰性数组之类的东西是不明智的。
Using Enumerable instead can work nicely in some situations, but differs from lazy lists in some points: methods like map and filter won't be evaluated lazily (so they won't work on infinite enumerables) and elements that have been calculated once aren't stored, so if you access an element twice, it's calculated twice.
使用枚举而不是可以在某些情况下很好地工作,但不同于懒惰的列表在某些点:方法映射和过滤器不会评估延迟(所以他们不会无限可列举的工作)和元素,一旦不存储,计算两次如果你访问一个元素,它是计算两次。
If you want the exact behavior of haskell's lazy lists in ruby, there's a lazylist gem which implements lazy lists.
如果您想要haskell的惰性列表在ruby中的确切行为,那么有一个实现惰性列表的lazylist gem。
#6
1
This will loop to infinity:
这将循环到无穷:
0.step{|i| puts i}
This will loop to infinity twice as fast:
它会以两倍的速度循环到无穷大:
0.step(nil, 2){|i| puts i}
This will go to infinity, only if you want it to (results in an Enumerator).
这将趋于无穷大,只有在您希望的情况下(结果是一个枚举数)。
table_of_3 = 0.step(nil, 3)
#7
-3
Ruby Arrays dynamically expand as needed. You can apply blocks to them to return things like even numbers.
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]
Does this help?
这有帮助吗?
#1
40
With Ruby 1.9 you can use the Enumerator class. This is an example from the docs:
使用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]
Also, this is a nice trick:
另外,这是一个很好的技巧:
Infinity = 1.0/0
range = 5..Infinity
p range.take(10) #=> [5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
This one only works for consecutive values though.
但是这个只适用于连续的值。
#2
20
Recently Enumerable::Lazy has been added to ruby trunk. We'll see it in ruby 2.0. In particular:
最近可枚举的::Lazy已添加到ruby主干中。我们将在ruby 2.0中看到它。特别是:
a = data.lazy.map(&:split).map(&:reverse)
will not be evaluated immediately.
The result is instance of Enumerable::Lazy, that can be lazy chained any further. If you want to get an actual result - use #to_a
, (#take(n)
#take
is now lazy too, use #to_a
or #force
), etc.
If you want more on this topic and my C patch - see my blog post Ruby 2.0 Enumerable::Lazy
不会立即进行评估。结果是Enumerable:::Lazy,它可以被惰性链接得更远。如果你想要得到一个真实的结果——使用#to_a, #take(n) (#take现在也是懒惰的,使用#to_a或#force)等等
#3
6
Lazy range (natural numbers):
懒惰的范围(自然数):
Inf = 1.0/0.0
(1..Inf).take(3) #=> [1, 2, 3]
Lazy range (even numbers):
懒惰的范围(偶数):
(0..Inf).step(2).take(5) #=> [0, 2, 4, 6, 8]
Note, you can also extend Enumerable
with some methods to make working with lazy ranges (and so on) more convenient:
注意,您还可以使用一些方法扩展Enumerable,以便使用lazy ranges(等等)更加方便:
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]
More info here: http://banisterfiend.wordpress.com/2009/10/02/wtf-infinite-ranges-in-ruby/
更多信息:http://banisterfiend.wordpress.com/2009/10/02/wtf-infinite-ranges-in-ruby/
There are also implementations of lazy_map, and lazy_select for the Enumerator
class that can be found here: http://www.michaelharrison.ws/weblog/?p=163
也有lazy_map和lazy_select的实现,用于可以在这里找到的Enumeratorclass: http://www.michaelharrison.ws/weblog/?
#4
4
In Ruby 2.0.0, they were introduced new method "Lazy" in Enumerable class.
在Ruby 2.0.0中,在可枚举类中引入了新的方法“Lazy”。
You can check the lazy function core and usage here..
您可以在这里查看惰性函数核心和用法。
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
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
#5
1
As I already said in my comments, implementing such a thing as lazy arrays wouldn't be sensible.
正如我在评论中已经说过的,实现诸如惰性数组之类的东西是不明智的。
Using Enumerable instead can work nicely in some situations, but differs from lazy lists in some points: methods like map and filter won't be evaluated lazily (so they won't work on infinite enumerables) and elements that have been calculated once aren't stored, so if you access an element twice, it's calculated twice.
使用枚举而不是可以在某些情况下很好地工作,但不同于懒惰的列表在某些点:方法映射和过滤器不会评估延迟(所以他们不会无限可列举的工作)和元素,一旦不存储,计算两次如果你访问一个元素,它是计算两次。
If you want the exact behavior of haskell's lazy lists in ruby, there's a lazylist gem which implements lazy lists.
如果您想要haskell的惰性列表在ruby中的确切行为,那么有一个实现惰性列表的lazylist gem。
#6
1
This will loop to infinity:
这将循环到无穷:
0.step{|i| puts i}
This will loop to infinity twice as fast:
它会以两倍的速度循环到无穷大:
0.step(nil, 2){|i| puts i}
This will go to infinity, only if you want it to (results in an Enumerator).
这将趋于无穷大,只有在您希望的情况下(结果是一个枚举数)。
table_of_3 = 0.step(nil, 3)
#7
-3
Ruby Arrays dynamically expand as needed. You can apply blocks to them to return things like even numbers.
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]
Does this help?
这有帮助吗?