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

Ruby: удалить и вернуть значение массива на основе условия поиска блока

Есть ли встроенный способ удаления значения из массива на основе условия блока, возвращающего true, и возврата значения, которое было удалено?

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

array = [1,2,3,4,5,6,7,8,9,10]

index = array.index {|v| v == 5} # returns index if block is true

value = array.delete_at(index) # deletes and returns element at index

value тогда 5

4b9b3361

Ответ 1

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

reject = []
 => [] 
content = [1,2,3,4,5,6,7,8,9]
 => [1, 2, 3, 4, 5, 6, 7, 8, 9] 
content.delete_if {|v| reject << v if v > 5}
 => [1, 2, 3, 4, 5] 
reject
 => [6, 7, 8, 9] 
content
 => [1, 2, 3, 4, 5] 

Ответ 2

Вам действительно нужно удалять элементы из исходного массива или вы действительно просто пытаетесь разбить его на две части, основанные на некоторых состояние? Если последнее, то:

accepted = [ ]
rejected = [ ]
original.each { |e| (want_this_one(e) ? accepted : rejected).push(e) }

или

parts = original.inject({ :accepted => [ ], :rejected => [ ] }) do |accumulator, e|
  if(want_this_one(e))
    accumulator[:accepted].push(e)
  else
    accumulator[:rejected].push(e)
  end
  accumulator
end

И затем простая оболочка метода, которая упрощает доставку блока:

def categorize(array)
  categories = array.inject({ :accepted => [ ], :rejected => [ ] }) do |accumulator, e|
    if(yield e)
      accumulator[:accepted].push(e)
    else
      accumulator[:rejected].push(e)
    end
    accumulator
  end
  return categories[:accepted], categories[:rejected]
end

kept, deleted = categorize([1, 2, 3, 4, 5]) { |n| n % 2 == 0 }
# kept    = [2, 4]
# deleted = [1, 3, 5]

Или вы можете просто использовать Enumerable#partition, чтобы разделить массив на две части.

Если вам действительно нужно изменить массив на месте, то эта версия Wes должна сделать трюк:

def slice_out(array)
  dead = [ ]
  array.delete_if do |e|
    if(yield e)
      dead.push(e)
      true
    else
      false  
    end
  end
  dead
end

a = [1,2,3,4]
x = slice_out(a) { |n| n % 2 == 0 }
# a == [1, 3]
# x == [2, 4]

Ответ 3

Вы можете использовать раздел. Очевидно, что пример блока здесь не имеет полного смысла, но возвращает оба удаленных элемента и остается.

a = [1,2,3,4,5,6,7,8,9]
b, a = a.partition { |x| [1,3,5].include?(x) }

b # [1, 3, 5]
a # [2, 4, 6, 7, 8, 9]

Ответ 4

Это не будет работать для каждого варианта использования, но если вы извлекаете элементы по одному из массива в соответствии с некоторыми условиями, вы можете сделать это:

array = [1,2,3,4,5,6,7,8,9,10]
indexed_array = array.index_by { |a| a }  # or whatever your condition is
item = indexed_array.delete(5)
array = indexed_array.values

Ответ 5

вы можете использовать values_at например

>> array = [1,2,3,4,5,6,7,8,9,10]
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>> array.values_at(5)
=> [6]