【问题标题】:Add only unique objects to an array in JavaScript仅将唯一对象添加到 JavaScript 中的数组
【发布时间】:2013-06-25 09:07:39
【问题描述】:

假设我从这个开始:

var shippingAddresses = [
    {
      "firstname": "Kevin",
      "lastname": "Borders",
      "address1": "2201 N Pershing Dr",
      "address2": "Apt 417",
      "city": "Arlington",
      "state": "VA",
      "zip": "22201",
      "country": "US"
    }, 
    {
      "firstname": "Dan",
      "lastname": "Hess",
      "address1": "304 Riversedge Dr",
      "address2": "",
      "city": "Saline",
      "state": "MI",
      "zip": "48176",
      "country": "US"
    }
]

我使用它来预填充表单。
用户可以编辑 条目或添加 新条目。我需要防止他们添加重复项。

问题是我序列化的表单的结构和从数据库返回的这些值的顺序不一样,所以我有机会使用以下格式将一个项目插入到这个数组中:

{
  "country": "US",
  "firstname": "Kevin",
  "lastname": "Borders",
  "address1": "2201 N Pershing Dr",
  "address2": "Apt 417",
  "zip": "22201",                                    
  "city": "Arlington",
  "state": "VA"
}

与第一个条目相同,只是顺序不同。

我正在加载 underscorejs,所以如果有办法用那个库来处理它,那就太好了。如果有帮助,我也在使用 jQuery

目前我不确定如何继续。

【问题讨论】:

  • 你需要用_对对象的属性进行排序吗?
  • 我不需要对属性进行排序,不。我特别试图以与属性顺序无关的方式来做到这一点。
  • 您是否真的在比较序列化的 JSON 字符串,或者为什么您认为顺序很重要?向我们展示您用于防止重复的代码
  • 我现在不阻止重复,这就是我发布这个问题的原因。
  • 好的,我的答案的新编辑现在应该适用于可变属性定位的对象。

标签: javascript arrays json sorting underscore.js


【解决方案1】:

Underscore findWhere function 完全符合您的需要 - 它不是按对象身份搜索 indexOf,而是搜索属性与输入值相同的对象。

if (_.findWhere(shippingAddresses, toBeInserted) == null) {
    shippingAddresses.push(toBeInserted);
}

【讨论】:

  • 我认为这是最好的方法。特别是考虑到你有下划线。我可以重构我的代码以在没有下划线的情况下工作,但这是一种方法。
  • 由于宽松的比较==,此代码行为正确,但_.findWhere 必须针对undefined 而不是null 进行测试(根据underscore.js docs)。
  • @physiocoder: 正是我想要的 :-) 当然,如果你更喜欢 === undefined,你也可以使用它。
【解决方案2】:

使用 lodash union 方法的基本示例:

var a = [1,2,3];

// try to add "1" and "4" to the above Array
a = _.union(a, [1, 4]);

console.log(a);
<script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/4.13.1/lodash.min.js"></script>

虽然这不能直接回答这个问题,但它确实回答了如何向数组添加唯一值的更广泛的问题,并且像我一样,其他人可能会偶然发现谷歌的这个页面。

【讨论】:

    【解决方案3】:

    基于以下答案:"js-remove-an-array-element-by-index-in-javascript"

    https://stackoverflow.com/a/7142909/886092

    我正在使用以下简洁的成语,不需要 underscore.js 或任何其他框架。

    这是一个记录 DataTables jquery 插件的选定行和取消选定行的示例。 我保留了一个当前选定的 id 数组,并且我不想在数组中出现重复项:

    在咖啡脚本中

      fnRowSelected: (nodes) ->
        position = $selected.indexOf(nodes[0].id)
        unless ~position
          $selected.push nodes[0].id
        return
      fnRowDeselected: (nodes) ->
        position = $selected.indexOf(nodes[0].id)
        if ~position
          $selected.splice(position, 1)
    

    一般来说会

    position = myArray.indexOf(myval)
    unless ~position
      myArray.push myVal
    

    或在 JS 中

    var position;
    
    position = myArray.indexOf(myval);
    
    if (!~position) {
      myArray.push(myVal);
    }
    

    【讨论】:

    • 如果你用 JS 而不是 coffeescript 回答,也许你可能会获得更多的赞成票,因为这个问题清楚地询问了在 JS 中做这件事 :)
    【解决方案4】:

    使用 ECMAScript 2015 中的 Set() 的基本示例(无需库)

    Set 对象允许您存储任何类型的唯一值(无论是原始值还是对象引用)。如果传递了一个可迭代对象,它的所有元素都将被添加到新的Set 中。这里我只添加一个值:

    // original array with duplicates already present
    const numbers = [1, 1, 1, 2, 3, 100]
    
    // Use Set to remove duplicate elements from the array 
    // and keep your new addition from causing a duplicate.
    
    // New value (100) is not added since it exists (and array 
    // also is de-duped)
    console.log(Array.from(new Set([...numbers, 100])))
    // [1, 2, 3, 100]
    
    // New, non-existing value (101) is added (and array is de-duped)
    console.log(Array.from(new Set([...numbers, 101])))
    // [1, 2, 3, 100, 101]

    【讨论】:

    • 这个问题是专门要求objects,而不是integers。在对Set 执行添加时,由于其引用,它仍会认为添加的每个新对象都是唯一的。
    【解决方案5】:

    如果你想检查用户输入对象,你可以试试这个功能:

    var uniqueInput = {
                           "country": "UK",
                           "firstname": "Calvin",
                           "lastname": "Borders",
                           "address1": "2201 N Pershing Dr",
                           "address2": "Apt 417",
                           "city": "Arlington",
                           "state": "VA",
                           "zip": "22201"
    
                            };
    
    var duplicatedInput = {
                           "country": "US",
                           "firstname": "Kevin",
                           "lastname": "Borders",
                           "address1": "2201 N Pershing Dr",
                           "address2": "Apt 417",
                           "city": "Arlington",
                           "state": "VA",
                           "zip": "22201"
    
                            };
    
    var shippingAddresses = [{
                           "firstname": "Kevin",
                           "lastname": "Borders",
                           "address1": "2201 N Pershing Dr",
                           "address2": "Apt 417",
                           "city": "Arlington",
                           "state": "VA",
                           "zip": "22201",
                           "country": "US"
                            }, {
                                "firstname": "Dan",
                                "lastname": "Hess",
                                "address1": "304 Riversedge Dr",
                                "address2": "",
                                "city": "Saline",
                                "state": "MI",
                                "zip": "48176",
                                "country": "US"
                            }];
    
    function checkDuplication(checkTarget,source){
        _.each(source,function(obj){
            if(_.isEqual(checkTarget,obj)){ 
                alert("duplicated");
            }
        });
    }
    

    并尝试在不同的参数(uniqueInput 和 duplicatedInput)中调用此检查功能 我认为它可以检查您送货地址中的重复输入。

    checkDuplication(uniqueInput,shippingAddresses);
    checkDuplication(duplicatedInput,shippingAddresses);
    

    我创建了一个jsfiddle。你可以试试。 希望这对您有所帮助。

    【讨论】:

      【解决方案6】:

      编辑,这将适用于您的未排序属性示例:

      var normalized_array = _.map(shippingAddresses, function(a){ 
            var o = {}; 
            _.each(Object.keys(shippingAddresses[0]), function(x){o[x] = a[x]});
            return o;
      })
      var stringy_array = _.map(normalized_array, JSON.stringify);
      shippingAddresses = _.map(_.uniq(stringy_array), JSON.parse});
      

      我们可以用单线做到这一点,但它会超级难看:

      shippingAddresses_uniq = _.map(_.uniq(_.map(_.map(shippingAddresses, function(a){ var o = {}; _.each(Object.keys(shippingAddresses[0]), function(x){o[x] = a[x]}); return o; }), JSON.stringify)), JSON.parse});
      

      【讨论】:

      • 即使属性的顺序不同,这也适用于重复项?
      • 实际上,如果属性的顺序不同,它似乎不会。请稍等一下,让我解决这个问题。
      • ……但真的很丑。顺便说一句,你应该只使用 _.map(…, JSON.parse) 而不是那些不必要的包装器
      【解决方案7】:

      我认为你需要这个,

      注意: 不需要库。

      let array = [{ id: 1}, {id: 2}, {id: 3}];
      
      function addUniqeObj(data) {
        let index = -1;
      
        for(let i = 0, i < array.length; i++) {
          if(array[i].id === data.id) {
            index = i;
          }
        }
      
        if(index > -1) {
          array[index] = data;
        } else {
          array.push(data)
        }
      
      }
      

      【讨论】:

        猜你喜欢
        • 2016-02-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多