Arrays 使用特定属性标记并删除对象数组中的重复项以进行比较

Arrays 使用特定属性标记并删除对象数组中的重复项以进行比较,arrays,ruby,unique,Arrays,Ruby,Unique,我有一个如下所示的对象数组: [ { "field name" => "Account number", "data type" => "number", "mneumonic" => "ACTNUM", "field number" => "027" }, { "field name" => "Warning", "data type" => "code", "mneumonic" =>

我有一个如下所示的对象数组:

[
  {
    "field name" => "Account number",
    "data type" => "number",
    "mneumonic" => "ACTNUM",
    "field number" => "027"
  },
  {
    "field name" => "Warning",
    "data type" => "code",
    "mneumonic" => "WARN1",
    "field number" => "034:01"
  },
  {
    "field name" => "Warning",
    "data type" => "code",
    "mneumonic" => "WARN2",
    "field number" => "034:02"
  },
  .....
]
我需要搜索整个数组,并根据
“field name”
属性标记重复项。为此,我可以使用类似于
uniq{| I | I[“字段名”]}

但是,对于找到的任何重复项,最终未被删除的项需要添加一个属性:
multiple=>true
。我不在乎哪一个对象最终是留在数组中的对象,只要它标记了这个属性。因此,在上面的示例中运行函数可能会产生:

[
  {
    "field name" => "Account number",
    "data type" => "number",
    "mneumonic" => "ACTNUM",
    "field number" => "027",
  },
  {
    "field name" => "Warning",
    "data type" => "code",
    "mneumonic" => "WARN1",
    "field number" => "034:01",
    "multiple" => true
  },

  .....
]
除了删除重复项之外,我还需要确保数组的顺序不受函数的影响


最好的方法是什么?

这里有一个非常简单的解决方案:

array # => your array of objects
used_names = []
multiple_names = []
array.each do |hash|
  name = hash['field name']
  if used_names.include? name
    multiple_names << name
    array.delete hash
  else
    used_names << name
  end
end
array.each do |hash|
  if multiple_names.include? hash['field name']
    hash['multiple'] = true
  end
end
array#=>您的对象数组
已用名称=[]
多个_名称=[]
array.each do|散列|
name=hash['fieldname']
如果使用,包括哪些名称?名称

多个_名称此版本只计算“字段名称”出现的次数,如果大于1或不大于1,则根据需要更新哈希

field_name_counts = Hash.new 0

array.each do |hash|
  field_name = hash["field name"]
  field_name_counts[field_name] += 1
end

array.each do |hash|
  field_name = hash["field name"]
  if field_name_counts[field_name] > 1
    hash["multiple"] = true
  else
    hash["multiple"] = false
  end
end
使用此阵列:

a = [
  {
    "field name" => "Account number",
    "data type" => "number",
    "mneumonic" => "ACTNUM",
    "field number" => "027",
  },
  {
    "field name" => "Warning",
    "data type" => "code",
    "mneumonic" => "WARN1",
    "field number" => "034:01",
  },
  {
    "field name" => "Warning",
    "data type" => "code",
    "mneumonic" => "WARN2",
    "field number" => "034:02",
  },
]
此代码:

file_names = {}
a.select do
  |h| k = h["field name"]
  if file_names[k]
    file_names[k]["multiple"] = true
    false
  else
    file_names[k] = h
    true
  end
end
将提供:

[
  {
    "field name"   => "Account number",
    "data type"    => "number",
    "mneumonic"    => "ACTNUM",
    "field number" => "027"
  },
  {
    "field name"   => "Warning",
    "data type"    => "code",
    "mneumonic"    => "WARN1",
    "field number" => "034:01",
    "multiple"     => true
  }
]

此解决方案构建一个新阵列,排除重复项。对于原始数组中的每个项,它会检查是否存在已使用相同名称看到的
现有
项。如果是,它将现有项标记为
existing[“multiple”]=true
,并跳过该迭代

这具有在新数组中省略重复项并标记原始项的预期效果

unique_data = data.each_with_object([]) do |item, result|
  if (existing = result.find { |i| i["field name"] == item["field name"] })
    existing["multiple"] = true
    next
  end
  result << item
end
unique_data=data。每个带有_对象([])的_都做|项,结果|
if(existing=result.find{| i | i[“字段名”]==item[“字段名”]})
现有[“多个”]=true
下一个
结束

结果如果您使用的是Ruby v1.9+(其中哈希保证保持键插入顺序),那么您可以使用(aka
merge!
)的形式,该形式使用一个块来确定合并的两个哈希中存在的键的值
a
是@sawa给出的数组

a.each_with_object({}) do |f,g|
  g.update(f["field name"]=>f) { |_,h| h.merge("multiple"=>true) }
end.values
  #=> [{"field name"=>"Account number", "data type"=>"number",
  #     "mneumonic"=>"ACTNUM", "field number"=>"027"},
  #    {"field name"=>"Warning", "data type"=>"code", "mneumonic"=>"WARN1",
  #     "field number"=>"034:01", "multiple"=>true}] 

@余浩我看到你删除了我问题中提到的文件。为什么我不应该这样做呢?它只是指向
Array
Hash
参考手册的链接,可能是最常用的两个类。您也不是指某些特定的方法。任何Ruby专家都知道在哪里可以找到它们,所以我认为这不会给你的问题增加多少信息。你的数组无效。@sawa添加了逗号,很抱歉这不会删除重复项。这似乎不起作用。我想这是因为你在循环中使用了
delete
,它不起作用,因为我不小心将键命名为
field\u name
,而不是
field name
(带有空格)。哦,您的测试数据在第一个对象中有错误(未关闭的
,值之间没有逗号)。我已经更新并测试了答案。您是否在比我提供的数据集更大的数据集上测试了它?在
每个
中使用
删除
不会导致它跳过索引吗?迭代将继续,唯一可能不起作用的地方是当您的数组中有多个完全相同的对象时。如果是这种情况,simp只需将
each
更改为
each\u with\u index
,并使用
delete\u at(index)
而不是
delete
,这样您将只删除指定索引处的对象。