Эквивалентный из Ruby Enumerable.collect, который возвращает Счетное?

В этом коде я создаю массив строк "1" к "10 000":

array_of_strings = (1..10000).collect {|i| String(i)}

Действительно ли Ruby удаляет сердцевину API, позволяют получать счетный объект, который позволяет мне перечислить по тому же списку, генерация строковые значения по требованию, вместо того, чтобы генерировать массив строк?

Вот дальнейший пример, который, надо надеяться, разъясняет то, что я пытаюсь сделать:

def find_me_an_awesome_username
  awesome_names = (1..1000000).xform {|i| "hacker_" + String(i) }
  awesome_names.find {|n| not stackoverflow.userexists(n) }
end

Где xform метод, который я ищу. awesome_names является Счетным, таким образом, xform не создает 1 миллион массивов строк элемента, но просто генерирует и возвращает строки формы "хакер _ [N]" по требованию.

Между прочим, вот то, на что это могло бы быть похожим в C#:

var awesomeNames = from i in Range(1, 1000000) select "hacker_" + i;
var name = awesomeNames.First((n) => !stackoverflow.UserExists(n));

(Одно Решение)

Вот расширение Перечислителя, который добавляет xform метод. Это возвращает другой перечислитель, который выполняет итерации по значениям исходного перечислителя с преобразованием, к которому относятся это.

class Enumerator
  def xform(&block)
    Enumerator.new do |yielder|
      self.each do |val|
        yielder.yield block.call(val)
      end
    end
  end
end

# this prints out even numbers from 2 to 10:
(1..10).each.xform {|i| i*2}.each {|i| puts i}
8
задан mackenir 24 February 2010 в 20:56
поделиться

4 ответа

Ruby 2.0 представил Enumerable # lazy , который позволяет связать map , select и т. Д., И генерировать окончательные результаты только в конце with to_a , first и т. д. Вы можете использовать его в любой версии Ruby с require 'backports / 2.0.0 / enumerable / lazy' .

require 'backports/2.0.0/enumerable/lazy'
names = (1..Float::INFINITY).lazy.map{|i| "hacker_" + String(i) }
names.first # => 'hacker_1'

В противном случае вы можете использовать Enumerator.new {with_a_block} . Это нововведение в Ruby 1.9, поэтому требует 'backports / 1.9.1 / enumerator / new' , если он вам нужен в Ruby 1.8.x.

Согласно вашему примеру, следующий код не создаст промежуточный массив, а будет строить только необходимые строки:

require 'backports/1.9.1/enumerator/new'

def find_me_an_awesome_username
  awesome_names = Enumerator.new do |y|
    (1..1000000).each {|i| y.yield "hacker_" + String(i) }
  end
  awesome_names.find {|n| not stackoverflow.userexists(n) }
end

Вы даже можете заменить 100000 на 1.0 / 0 (т.е. бесконечность), если хотите.

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

module Enumerable
  def lazy_each
    Enumerator.new do |yielder|
      each do |value|
        yielder.yield(yield value)
      end
    end
  end
end

awesome_names = (1..100000).lazy_each{|i| "hacker_#{i}"}
6
ответ дан 5 December 2019 в 20:15
поделиться

Похоже, вам нужен объект Enumerator, но не совсем.

То есть объект Enumerator - это объект, который можно использовать для вызова next по запросу (а не each , который выполняет весь цикл). (Многие люди используют язык внутренних и внешних итераторов: каждый является внутренним, а перечислитель - внешним. Вы управляете им.)

Вот как может выглядеть перечислитель:

awesome_names = Enumerator.new do |y|
  number = 1
  loop do
    y.yield number
    number += 1
  end
end

puts awesome_names.next
puts awesome_names.next
puts awesome_names.next
puts awesome_names.next

Вот ссылка, для более подробного обсуждения того, как можно лениво использовать Enumerators в Ruby: http://www.michaelharrison.ws/weblog/?p=163

Также есть раздел об этом в книге Pickaxe ( Programming Руби Дэйва Томаса).

1
ответ дан 5 December 2019 в 20:15
поделиться
class T < Range
  def each
    super { |i| yield String(i) }
  end
end

T.new(1,3).each { |s| p s }
$ ruby rsc.rb
"1"
"2"
"3"

Следующее, что нужно сделать, - это вернуть перечислитель при вызове без блока ...

1
ответ дан 5 December 2019 в 20:15
поделиться

списки имеют метод each:

(1..100000).each
0
ответ дан 5 December 2019 в 20:15
поделиться
Другие вопросы по тегам:

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