红宝石仅拒绝哈希数组中的某些重复项

时间:2018-07-16 18:24:20

标签: ruby-on-rails ruby

我想根据重复次数(> = 3)拒绝哈希数组中的重复。

例如:重复的标准只是名称,而与数字无关。

  .woocommerce ul.products li.product a img 
  {
   height: 400px !important;
  }

我要拒绝重复两次以上的“名称”。 该函数应返回:

a = [{:name=>"John Doe1", :number=>"5551234567"},
         {:name=>"John Doe1", :number=>"5551234567"},
              {:name=>"John Doe2", :number=>"5557654321"},
               {:name=>"John Doe1", :number=>"5551234567"}]

我在下面尝试了这可能是错误的:

[{:name=>"John Doe2", :number=>"5557654321"}]

4 个答案:

答案 0 :(得分:3)

Enumerable#rejectEnumerable#count可能有帮助:

arr = [
    {:name=>"John Doe1", :number=>"5551234567"},
    {:name=>"John Doe1", :number=>"5551234567"},
    {:name=>"John Doe2", :number=>"5557654321"},
    {:name=>"John Doe1", :number=>"5551234567"}
]
p arr.reject { |hsh| arr.count(hsh) > 2 }
# => [{:name=>"John Doe2", :number=>"5557654321"}]

根据评论,添加用法Enumerable#map

names = arr.map { |hsh| hsh[:name] }
p arr.reject { |hsh| names.count(hsh[:name]) > 2 }

答案 1 :(得分:1)

这是O(n),在更大的列表上可能会做得更好:

a.group_by { |el| el[:name] }.reject { |_, v| v.size > 2 }.values.flatten

答案 2 :(得分:1)

假设我们给出以下数组(与问题中给出的数组不同)。

arr = [{ :name=>"John Doe1", :number=>"5551234567" },
       { :name=>"John Doe3", :number=>"5551234567" },
       { :name=>"John Doe1", :number=>"5551234567" },
       { :name=>"John Doe2", :number=>"5557654321" },
       { :name=>"John Doe3", :number=>"5551234567" },
       { :name=>"John Doe1", :number=>"5551234567" }]

我们可以如下获得所需的值。

arr.values_at(*arr.each_with_index.with_object({}) { |(g,i),h| (h[g] ||= []) << i }.
    values.
    select { |a| a.size < 3 }.
    flatten.
    sort)
  #=> [{:name=>"John Doe3", :number=>"5551234567"},
  #    {:name=>"John Doe2", :number=>"5557654321"},
  #    {:name=>"John Doe3", :number=>"5551234567"}]

步骤如下。

enum0 = arr.each_with_index
  #=> #<Enumerator: [{:name=>"John Doe1", :number=>"5551234567"},
  #                  {:name=>"John Doe3", :number=>"5551234567"},
  #                   ...
  #                  {:name=>"John Doe1", :number=>"5551234567"}]:each_with_index>
enum1 = enum0.with_object({})
  #=> #<Enumerator:
  #     #<Enumerator: [{:name=>"John Doe1", :number=>"5551234567"},
  #                    {:name=>"John Doe3", :number=>"5551234567"},
  #                    ...
  #                    {:name=>"John Doe1", :number=>"5551234567"}]:each_with_index>
  #   :with_object({})>
b = enum1.each { |(g,i),h| (h[g] ||= []) << i }
  #=> {{:name=>"John Doe1", :number=>"5551234567"}=>[0, 2, 5],
  #    {:name=>"John Doe3", :number=>"5551234567"}=>[1, 4],
  #    {:name=>"John Doe2", :number=>"5557654321"}=>[3]}
c = b.values
  #=> [[0, 2, 5], [1, 4], [3]]
d = c.select { |a| a.size < 3 }
  #=> [[1, 4], [3]]
f = e.sort
  #=> [1, 3, 4]
arr.values_at(*f)
  #=> [{:name=>"John Doe3", :number=>"5551234567"},
  #    {:name=>"John Doe2", :number=>"5557654321"},
  #    {:name=>"John Doe3", :number=>"5551234567"}]

答案 3 :(得分:0)

整个答案已根据@CarySwoveland的启发进行了重新编写(对于以前的实现,请随时查看所做的编辑)。

这2个选项似乎是处理这种情况的最有效方法

a.group_by { |el| el[:name] }.each_with_object([]) do |(_, v),obj| 
  obj.concat(v) if v.size < 3 
end
#or 
a.group_by { |el| el[:name] }.flat_map { |_, v| v if v.size < 3 }.compact