代码之家  ›  专栏  ›  技术社区  ›  Luke

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

  •  1
  • Luke  · 技术社区  · 10 年前

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

    [
      {
        "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["field name"] }

    但是,对于找到的任何重复项,最终未删除的项需要添加一个属性: 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
      },
    
      .....
    ]
    

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

    解决这个问题的最佳方法是什么?

    5 回复  |  直到 10 年前
        1
  •  1
  •   sawa    10 年前

    使用此阵列:

    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
      }
    ]
    
        2
  •  1
  •   Piotr Kruczek Andrey Ivanov    10 年前

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

    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
    
        3
  •  0
  •   vikram7    10 年前

    这个版本只计算“域名”出现的次数,如果它大于或不大于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
    
        4
  •  0
  •   Matt Brictson    10 年前

    此解决方案构建排除重复项的新阵列。对于原始数组中的每个项,它检查是否存在 existing 已看到同名的项目。如果是,则将该现有项标记为 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
    
        5
  •  0
  •   Cary Swoveland    10 年前

    如果您使用的是Ruby v1.9+(其中哈希保证保持密钥插入顺序),您可以使用以下形式 Hash#update (又名 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}]