我正在尝试通过删除与唯一ID匹配的值来修改数组,但是一旦该数组的前5个值有效(即它们的ID与不想要的ID不匹配),然后停止。如果数组的计数<= 5,则满足以下条件:
all_items = [{"id" => "id01"},{"id" => "id02"},{"id" => "id03"},{"id" => "id04"}]
exclude_ids = ["id01","id02"]
all_items.delete_if { |item| exclude_ids.include?(item["id"])}
,期望的输出为[{"id" => "id03"},{"id" => "id04"}]
。
但是在数组的总数大于等于5的情况下,我只想删除 尽可能多的第一项,直到前5个元素(all_items[0..4]
)在设定的条件内均有效,然后停止迭代。如果我要这样做:
all_items = [{"id" => "id01"},{"id" => "id02"},{"id" => "id03"},{"id" => "id04"},{"id" => "id05"},{"id" => "id06"},{"id" => "id07"},{"id" => "id08"},{"id" => "id09"},{"id" => "id10"}]
exclude_ids = ["id01","id02","id07"]
all_items.delete_if { |item| exclude_ids.include?(item["id"])}
return all_items[0..4]
我确实获得了所需的输出[{"id" => "id03"},{"id" => "id04"},{"id" => "id05"},{"id" => "id06"},{"id" => "id08"}]
。但是我希望delete_if
一旦到达all_items[0..4]
已经包含5个有效元素的位置就完全停止。在这种情况下,我希望它在{"id" => "id08"}
之后中断,甚至不检查其余值。 (但是,如果delete_if
在运行时,总计数降至5以下,则它应继续遍历所有剩余元素,因为它属于我上面发布的第一段代码的类别,其中计数<= 5。)
我知道有一个delete_if.with_index
,但是我不确定在这种情况下是否合适,尤其是因为删除项目后索引会发生变化。
总结一下我的问题:有没有一种方法可以从数组中删除所需的首项,直到array[0..x]
被所需的值填充,然后一旦x的计数停止,就停止检查/删除所有剩余项到达了?
答案 0 :(得分:1)
如果从原始对象中删除,则会得到所有尚未删除的项目。因此,我认为最好只将所需的项目移动到新对象中:
all_items.each_with_object([]) { |item, ary| ary << item if !exclude_ids.include?(item["id"]) and ary.size < 5 }
#=> [{"id"=>"id03"}, {"id"=>"id04"}, {"id"=>"id05"}, {"id"=>"id06"}, {"id"=>"id08"}]
答案 1 :(得分:1)
termination_threshold = 5
all_items = (1..20).to_a
#=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
exclusions = [1,2,7]
all_items.reject! do |n|
break if termination_threshold.zero?
exclude = exclusions.include? n
termination_threshold -= 1 if exclude
exclude
end
#=> [3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
all_items
#=> [3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
如果只需要包含termination_threshold
的前all_items
个有效元素的数组,则可以使用以下内容:
all_items.each_with_object([]) do |e,arr|
arr << e unless exclusions.include?(e)
break arr if arr.size == termination_threshold
end
#=> [3, 4, 5, 6, 8]
答案 2 :(得分:1)
您可以使用Enumerator::Lazy来实现所需的目标:
all_items = [{"id" => "id01"},{"id" => "id02"},{"id" => "id03"},{"id" => "id04"},{"id" => "id05"},{"id" => "id06"},{"id" => "id07"},{"id" => "id08"},{"id" => "id09"},{"id" => "id10"}]
exclude_ids = ["id01","id02","id07"]
all_items.lazy.reject {|item| exclude_ids.include?(item['id']) }.first(5)