Ruby:根据块查找条件删除并返回一个数组值

时间:2022-09-10 23:27:17

Is there a built-in way to delete a value from an array, based on a block condition returning true, and return the value that was deleted?

是否有内置方法从数组中删除值,基于块条件返回true,并返回已删除的值?

This is a simplified version of what I'm trying to do, but it seems like there has to be a better way:

这是我正在尝试做的简化版本,但似乎必须有更好的方法:

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 is then 5

那么价值是5

4 个解决方案

#1


21  

You can't update the array in place and get a return of a different set of values that are deleted. You can do the following using delete_if to remove values and capture the ones removed by the logic in the block:

您无法更新阵列并返回已删除的另一组值。您可以使用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


4  

Do you really need to delete items from the original array or are you really just trying to split it into two pieces based on some condition? If the latter, then:

你真的需要从原始数组中删除项目,还是只是想根据某些条件将它分成两部分?如果是后者,那么:

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

or

要么

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

And then a simple method wrapper to make it easy to supply a block:

然后是一个简单的方法包装器,以便轻松提供块:

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]

Or you could just use Enumerable#partition to split the array into two pieces.

或者您可以使用Enumerable#partition将数组拆分为两部分。

If you really need to modify the array in-place then this version of Wes's should do the trick:

如果你真的需要就地修改数组,那么这个版本的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


1  

You can use partition. Obviously the block example here doesn't make complete sense but returns both deleted items and left over.

你可以使用分区。显然这里的块示例没有完全意义,但返回已删除的项目并留下。

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


-5  

you can use values_at eg

你可以使用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]

#1


21  

You can't update the array in place and get a return of a different set of values that are deleted. You can do the following using delete_if to remove values and capture the ones removed by the logic in the block:

您无法更新阵列并返回已删除的另一组值。您可以使用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


4  

Do you really need to delete items from the original array or are you really just trying to split it into two pieces based on some condition? If the latter, then:

你真的需要从原始数组中删除项目,还是只是想根据某些条件将它分成两部分?如果是后者,那么:

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

or

要么

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

And then a simple method wrapper to make it easy to supply a block:

然后是一个简单的方法包装器,以便轻松提供块:

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]

Or you could just use Enumerable#partition to split the array into two pieces.

或者您可以使用Enumerable#partition将数组拆分为两部分。

If you really need to modify the array in-place then this version of Wes's should do the trick:

如果你真的需要就地修改数组,那么这个版本的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


1  

You can use partition. Obviously the block example here doesn't make complete sense but returns both deleted items and left over.

你可以使用分区。显然这里的块示例没有完全意义,但返回已删除的项目并留下。

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


-5  

you can use values_at eg

你可以使用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]