Подтвердить что ты не робот

Ускорение .each {} итерации в начале Ruby

код:

 c = 0  
 items.each { |i|  
   puts i.to_s    
   # if c > 9 escape the each iteration early - and do not repeat  
   c++  
 }  

Я хочу захватить первые 10 элементов, а затем оставить цикл "каждый".

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

4b9b3361

Ответ 1

В то время как решение break работает, я думаю, что более функциональный подход действительно подходит для этой проблемы. Вы хотите, чтобы take первые 10 элементов и напечатали их, попробуйте

items.take(10).each { |i| puts i.to_s }

Ответ 2

В Ruby нет оператора ++. Он также соглашается использовать do и end для многострочных блоков. Изменение вашего решения дает:

c = 0  
items.each do |i|  
  puts i.to_s    
  break if c > 9
  c += 1 
end

Или также:

items.each_with_index do |i, c|  
  puts i.to_s    
  break if c > 9
end

Смотрите each_with_index, а также Программирование Ruby Break, Redo, и далее.

Обновление: Chuck answer с диапазонами больше Ruby-like и nimrodm answer с использованием take еще лучше.

Ответ 3

break работает для ускорения работы из цикла, но для него более идиоматично делать items[0..9].each {|i| puts i}. (И если все, что вы делаете, буквально печатает элементы без каких-либо изменений, вы можете просто сделать puts items[0..9].)

Ответ 4

Другой вариант:

puts items.first(10)

Обратите внимание, что это отлично работает с массивами менее 10 элементов:

>> nums = (1..5).to_a
=> [1, 2, 3, 4, 5]
>> puts nums.first(10)
1
2
3
4
5

(Еще одно замечание: многие люди предлагают некоторую форму puts i.to_s, но в таком случае не является .to_s избыточным? puts будет автоматически вызывать .to_s на нестрочном напечатайте его, подумал я. Вам понадобится .to_s, если вы хотите сказать puts 'A' + i.to_s или тому подобное.)

Ответ 5

Другой вариант:

items.first(10).each do |i|
  puts i.to_s
end

Это немного легче для меня, чем взломать итератор, и сначала вернет только столько элементов, сколько доступно, если их недостаточно.

Ответ 6

Означает ли это, что вы хотите?

10.times { |i|
  puts items[i].to_s
}

Ответ 7

items.each_with_index { |i, c| puts i and break if c <= 9 }

Ответ 8

Было спрошено:

Я хочу захватить первые 10 элементов, а затем оставить цикл "каждый".

Используйте throw и catch, чтобы выполнить это, с небольшими изменениями в примере:

catch(:done) do
    c = 0
    collected = []
    items.each do |item|
        collected << item
        throw(:done, collected) if c == 9 # started at 0
        c += 1
    end
    collected # if the list is less than 10 long, return what was collected
end

Просто throw метка :done с collected и catch, которая ждет :done, вернет collected.

И немного "рубить":

catch(:done) do
    items.inject([]) do |collected, item|
        throw(:done, collected) if collected.size == 10
        collected << item # collected gets returned here and populates the first argument of this block
    end
end

Я не знаю, почему некоторые люди отказываются использовать inject и вместо этого используют reduce (они эквивалентны), когда ясно, что пустой массив, присвоенный inject([]), вводится item s! Во всяком случае, inject вернет collected, если их меньше 10.

Большинство ответов пытаются ответить на вопрос, что может быть целью вопроса вместо того, что было задано, и items.take(10) имеет смысл в этом случае. Но я могу себе представить, что хочу захватить первые предметы, которые соответствуют моему бюджету в 100 долларов. Тогда вы можете просто:

catch(:done) do
    items.inject({items: [], budget: 100}) do |ledger, item|
        remainder = ledger[:budget] - item.price
        if remainder < 0
            throw(:done, ledger)
        else
            ledger.tap do |this|
                this[:items] << item
                this[:budget] = remainder
            end # tap just returns what is being tapped into, in this case, ledger
        end
    end
end