Удаление во время итерации в Ruby?

Я перебираю очень большой набор строк, который перебирает меньший набор строк. Из-за размера этот метод требует времени, поэтому, чтобы ускорить его, я пытаюсь удалить строки из меньшего набора, который больше не нужно использовать, по ходу дела. Ниже мой текущий код:

    Ms::Fasta.foreach(@database) do |entry|
        all.each do |set|
            if entry.header[1..40].include? set[1] + "|"
                startVal = entry.sequence.scan_i(set[0])[0]

                if startVal != nil
                    @locations << [set[0], set[1], startVal, startVal + set[1].length]
                    all.delete(set)
                end
            end
        end
    end

Проблема, с которой я сталкиваюсь, заключается в том, что простой способ, array.delete(string), эффективно добавляет оператор break во внутренний цикл, что искажает результаты. Единственный способ, которым я знаю, как это исправить, это сделать это:

Ms::Fasta.foreach(@database) do |entry|
        i = 0

        while i < all.length
            set = all[i]

            if entry.header[1..40].include? set[1] + "|"
                startVal = entry.sequence.scan_i(set[0])[0]

                if startVal != nil
                    @locations << [set[0], set[1], startVal, startVal + set[1].length]
                    all.delete_at(i)
                    i -= 1
                end
            end

            i += 1
        end
    end

Мне это кажется каким-то небрежным. Есть лучший способ сделать это?


person Jesse Jashinsky    schedule 29.05.2010    source источник
comment
проще сделать что? чего вы пытаетесь достичь?   -  person wilhelmtell    schedule 29.05.2010
comment
не могли бы вы не принимать свой собственный ответ ниже? это явно не лучший вариант   -  person WattsInABox    schedule 14.03.2015


Ответы (2)


используйте 1_

array.delete_if do |v|
    if v.should_be_deleted?
        true
    else
        v.update
        false
    end
end
person horseyguy    schedule 29.05.2010
comment
Смешно, если :). `array.delete_if { |v| v.следует_быть_удаленным? }` - person Yossi; 30.05.2010
comment
Это имело бы смысл, если бы он хотел запустить v.update любым элегантным способом :) - person trisweb; 22.11.2012
comment
К вашему сведению, удаление происходит немедленно, поэтому, если блок поднимается, изменения все равно будут отражены. - person Carson Reinke; 13.03.2014
comment
Руби так весело - person zkytony; 22.06.2016

используйте 'arr.shift'

a=[1,2,3,4]
while(a.length!=0)
  print a
  a.shift
  print "\n"
end

Выход:

[1, 2, 3, 4]
[2, 3, 4]
[3, 4]
[4]

person Abhishek    schedule 14.03.2013
comment
это не сработает ``` a = [1,2,3,4] a.each do помещает a.shift end 1 2 =› [3, 4] ``` - person Ivan Shamatov; 20.07.2016
comment
@Ivan спасибо, что указали на это. В прошлый раз я не проверял каждое действие для массива, но был уверен, что сдвиг выполнит требуемую работу. Так что отредактировал сейчас. Проверь это! - person Abhishek; 20.07.2016
comment
кроме того, Array#shift неэффективен, приведет к времени выполнения O (n²). - person Beni Cherniavsky-Paskin; 28.08.2017