【问题标题】:Array.push() if does not exist?Array.push() 如果不存在?
【发布时间】:2010-12-31 14:16:28
【问题描述】:

如果两个值都不存在,我该如何推入一个数组?这是我的数组:

[
    { name: "tom", text: "tasty" },
    { name: "tom", text: "tasty" },
    { name: "tom", text: "tasty" },
    { name: "tom", text: "tasty" },
    { name: "tom", text: "tasty" }
]

如果我尝试使用 name: "tom"text: "tasty" 再次推送到数组中,我不希望发生任何事情......但如果它们都不存在,那么我希望它到 .push()

我该怎么做?

【问题讨论】:

  • 使用字典(哈希/树)而不是数组。
  • 这些都可以在 javascript 中使用吗?
  • 使用Set
  • Set 不适用于对象数组

标签: javascript arrays json push not-exists


【解决方案1】:

我已经解决了这个问题,我做了一个简单的原型,如果你喜欢它就使用它

Array.prototype.findOrPush = function(predicate, fallbackVal) {
    let item = this.find(predicate)
    if(!item){
        item = fallbackVal
        this.push(item)
    }
    return item
}

let arr = [{id: 1}]
let item = arr.findOrPush(e => e.id == 2, {id: 2})
console.log(item) // {id: 2} 

// will not push and just return existing value
arr.findOrPush(e => e.id == 2, {id: 2}) 
conslog.log(arr)  // [{id: 1}, {id: 2}]

【讨论】:

    【解决方案2】:

    这个问题有点老了,但我的选择:

        let finalTab = [{id: 1, name: 'dupont'}, {id: 2, name: 'tintin'}, {id: 3, name:'toto'}]; // Your array of object you want to populate with distinct data
        const tabToCompare = [{id: 1, name: 'dupont'}, {id: 4, name: 'tata'}]; // A array with 1 new data and 1 is contain into finalTab
        
        finalTab.push(
          ...tabToCompare.filter(
            tabToC => !finalTab.find(
              finalT => finalT.id === tabToC.id)
          )
        ); // Just filter the first array, and check if data into tabToCompare is not into finalTab, finally push the result of the filters
    
        console.log(finalTab); // Output : [{id: 1, name: 'dupont'}, {id: 2, name: 'tintin'}, {id: 3, name: 'toto'}, {id: 4, name: 'tata'}];
    

    【讨论】:

      【解决方案3】:

      我的选择是使用.includes() 来扩展 Array.prototype,正如@Darrin Dimitrov 建议的那样:

      Array.prototype.pushIfNotIncluded = function (element) {
          if (!this.includes(element)) {
            this.push(element);
          }
      }
      

      只要记住 includes 来自 es6 并且不适用于 IE: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes

      【讨论】:

        【解决方案4】:

        使用Array.findIndex 函数很容易做到,它接受一个函数作为参数:

        var arrayObj = [{name:"bull", text: "sour"},
            { name: "tom", text: "tasty" },
            { name: "tom", text: "tasty" }
        ]
        var index = arrayObj.findIndex(x => x.name=="bob"); 
        // here you can check specific property for an object whether it exist in your array or not
        
        index === -1 ? arrayObj.push({your_object}) : console.log("object already exists")
         
        

        【讨论】:

        • 与在数组中添加元素(如果不存在)最相关
        【解决方案5】:

        推送后删除重复项

        如果您已经有一个包含重复项的数组,请将对象数组转换为字符串数组,然后使用Set() 函数消除重复项:

        // Declaring an array of objects containing duplicate objects
        let arrayOfObjects = [{name: "tom", text: "tasty"}, {name: "tom", text: "tasty"}];
        
        // Transforming array of objects into array of strings
        let arrayOfStrings = arrayOfObjects.map(obj => JSON.stringify(obj));
        
        // Creating a new set, Set() returns unique values by definition
        let uniqueSet = new Set(arrayOfStrings);
        
        // Transforming set into array and reversing strings to objects
        let uniqueArrayOfObjects = [...uniqueSet].map(elem => JSON.parse(elem));
        
        console.log(uniqueArrayOfObjects);
        // [{name: "tom", text: "tasty"}]
        

        推送前检查

        如果到目前为止您还没有重复项,并且您想在推送新元素之前检查重复项:

        // Declaring an array of objects without duplicates
        let arrayOfObjects = [{name: "tom", text: "tasty"}];
        
        // Transforming array of objects into array of strings
        let arrayOfStrings = arrayOfObjects.map(obj => JSON.stringify(obj));
        
        // Declaring new element as an example
        let newElem = {name: "tom", text: "tasty"};
        
        // Stringifying new element
        let newElemString = JSON.stringify(newElem);
        
        // At this point, check if the string is duplicated and add it to array
        !arrayOfStrings.includes(newElemString) && arrayOfObjects.push(newElem);
        
        console.log(arrayOfObjects);
        // [{name: "tom", text: "tasty"}]
        

        【讨论】:

          【解决方案6】:
          someArray = [{a: 'a1 value', b: {c: "c1 value"},
                       {a: 'a2 value', b: {c: "c2 value"}]
          newObject = {a: 'a2 value', b: {c: "c2 value"}}
          
          //New object which needs check for duplicity
          
          let isExists = checkForExists(newObject) {
              return someArray.some(function(el) {
                  return el.a === newObject.a && el.b.c === newObject.b.c;
              });
          }
          // write your logic here 
          // if isExists is true then already object in an array else you can add
          

          【讨论】:

          • 很好地使用.some!不过,您在两个数组对象上缺少结束 }
          【解决方案7】:

          动态推送

          var a = [
            {name:"bull", text: "sour"},
            {name: "tom", text: "tasty" },
            {name: "Jerry", text: "tasty" }
          ]
          
          function addItem(item) {
            var index = a.findIndex(x => x.name == item.name)
            if (index === -1) {
              a.push(item);
            }else {
              console.log("object already exists")
            }
          }
          
          var item = {name:"bull", text: "sour"};
          addItem(item);
          

          简单的方法

          var item = {name:"bull", text: "sour"};
          a.findIndex(x => x.name == item.name) == -1 ? a.push(item) : console.log("object already exists")
          

          如果数组只包含原始类型/简单数组

          var b = [1, 7, 8, 4, 3];
          var newItem = 6;
          b.indexOf(newItem) === -1 && b.push(newItem);
          

          【讨论】:

          • 手部健康。简单而美丽的解决方案@Gopala raja naika
          • 这个 a.findIndex(x => x.name == item.name) 非常简单,非常有用。谢谢
          【解决方案8】:

          这里你有一种方法可以在一行中为两个数组完成:

          const startArray = [1,2,3,4]
          const newArray = [4,5,6]
          
          const result = [...startArray, ...newArray.filter(a => !startArray.includes(a))]
          
          console.log(result);
          //Result: [1,2,3,4,5,6]
          

          【讨论】:

            【解决方案9】:

            简单的代码,如果“indexOf”返回“-1”,则表示该元素不在数组内,那么条件“=== -1”检索真/假。

            '&&' 操作符的意思是'and',所以如果第一个条件为真,我们将它推送到数组中。

            array.indexOf(newItem) === -1 && array.push(newItem);
            

            【讨论】:

            • @D.Lawrence 是的,现在好多了。
            • 还有其他可接受的答案提供了 OP 的问题,它们是前一段时间发布的。发布答案 see: How do I write a good answer? 时,请确保添加新的解决方案或更好的解释,尤其是在回答较老的问题时。
            • 我认为这是一个很好的答案和更好的解决方案,所以我投了赞成票。我不明白@help-info.de 的评论,尤其是这里还有其他很糟糕的答案。
            • 没有解决问题,一旦数组中有对象就不行了
            【解决方案10】:

            a 是您拥有的对象数组

            a.findIndex(x => x.property=="WhateverPropertyYouWantToMatch") <0 ? 
            a.push(objectYouWantToPush) : console.log("response if object exists");
            

            【讨论】:

              【解决方案11】:

              我想我在这里回答为时已晚,但这是我最终为我写的邮件管理器想出的。作品就是我所需要的。

              window.ListManager = [];
              $('#add').click(function(){
              //Your Functionality
                let data =Math.floor(Math.random() * 5) + 1 
                
                if (window.ListManager.includes(data)){
                    console.log("data exists in list")
                }else{
                     window.ListManager.push(data);
                }
                
                
                $('#result').text(window.ListManager);
              });
              <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
              <h1>Unique List</h1>
              
              <p id="result"></p>
              <button id="add">Add to List</button>

              【讨论】:

                【解决方案12】:

                我建议你使用Set

                集合只允许唯一条目,这会自动解决您的问题。

                集合可以这样声明:

                const baz = new Set(["Foo","Bar"])
                

                【讨论】:

                • 感谢@Michael 指出这一点。当我们想要以最小的努力维护不同的数据时,这是一个很好的解决方案。 FWIW,重要的是要注意数组性能更好,因为它需要更少的 CPU 来获取需要的元素。
                • 这个问题是关于Array.push,所以Set.add是等价的。
                • @BenjaminLöffel 我希望 Set 被实现为哈希,它的性能与迭代项目的数组一样好。当然,它在不重复插入时会表现得更好。
                【解决方案13】:

                简短示例:

                if (typeof(arr[key]) === "undefined") {
                  arr.push(key);
                }
                

                【讨论】:

                • 不正确。我们对推送键不感兴趣,我们想推送一个名称-值对,但前提是它不存在。
                【解决方案14】:

                不确定速度,但stringification + indexOf 是一种简单的方法。从将数组转换为字符串开始:

                let strMyArray = JSON.stringify(myArray);
                

                那么对于一系列的属性值对你可以使用:

                if (strMyArray.indexOf('"name":"tom"') === -1 && strMyArray.indexOf('"text":"tasty"') === -1) {
                   myArray.push({ name: "tom", text: "tasty" });
                }
                

                查找整个对象更简单:

                if (strMyArray.indexOf(JSON.stringify(objAddMe) === -1) { 
                   myArray.push(objAddMe);
                }
                

                【讨论】:

                  【解决方案15】:

                  对于字符串数组(但不是对象数组),您可以通过调用.indexOf() 来检查项目是否存在,如果不存在则只需将项目 到数组中:

                  var newItem = "NEW_ITEM_TO_ARRAY";
                  var array = ["OLD_ITEM_1", "OLD_ITEM_2"];
                  
                  array.indexOf(newItem) === -1 ? array.push(newItem) : console.log("This item already exists");
                  
                  console.log(array)

                  【讨论】:

                  • 不知道为什么这没有被标记为正确。它不使用任何外部组件,不需要创建扩展并且非常简单。操作问题的完美答案。
                  • 在最初的问题中,数组的值是对象,而不是字符串(如果值是对象,这个解决方案就不能正常工作)。
                  • @EmilPedersen - 不是真的。尝试if (a.indexOf({ name: "tom", text: "tasty" })!=-1) a.push({ name: "tom", text: "tasty" }) 两次。它将添加一个“相似”对象两次。
                  • 这个答案应该被删除,因为它在客观上是错误的,但仍然吸引了最多的点赞。
                  • 这不是一个正确的答案,为什么被接受?它只适用于 Js 数组,不适用于数组中的对象。
                  【解决方案16】:

                  如果有人有不太复杂的要求,这是我对简单字符串数组的答案的改编:

                  Array.prototype.pushIfNotExist = function(val) {
                      if (typeof(val) == 'undefined' || val == '') { return; }
                      val = $.trim(val);
                      if ($.inArray(val, this) == -1) {
                          this.push(val);
                      }
                  };
                  

                  更新:将 indexOf 和 trim 替换为 jQuery 替代品以实现 IE8 兼容性

                  【讨论】:

                  • 这是一个不错的解决方案,但为什么要使用 trim?
                  【解决方案17】:

                  像这样?

                  var item = "Hello World";
                  var array = [];
                  if (array.indexOf(item) === -1) array.push(item);
                  

                  有对象

                  var item = {name: "tom", text: "tasty"}
                  var array = [{}]
                  if (!array.find(o => o.name === 'tom' && o.text === 'tasty'))
                      array.push(item)
                  

                  【讨论】:

                  【解决方案18】:

                  这是一个对象比较的工作函数。在某些情况下,您可能需要比较很多字段。 只需循环数组并使用现有项和新项调用此函数。

                   var objectsEqual = function (object1, object2) {
                          if(!object1 || !object2)
                              return false;
                          var result = true;
                          var arrayObj1 = _.keys(object1);
                          var currentKey = "";
                          for (var i = 0; i < arrayObj1.length; i++) {
                              currentKey = arrayObj1[i];
                              if (object1[currentKey] !== null && object2[currentKey] !== null)
                                  if (!_.has(object2, currentKey) ||
                                      !_.isEqual(object1[currentKey].toUpperCase(), object2[currentKey].toUpperCase()))
                                      return false;
                          }
                          return result;
                      };
                  

                  【讨论】:

                    【解决方案19】:

                    我知道这是一个非常古老的问题,但如果您使用的是 ES6,则可以使用非常小的版本:

                    [1,2,3].filter(f => f !== 3).concat([3])
                    

                    非常简单,首先添加一个过滤器来删除该项目 - 如果它已经存在,然后通过 concat 添加它。

                    这是一个更现实的例子:

                    const myArray = ['hello', 'world']
                    const newArrayItem
                    
                    myArray.filter(f => f !== newArrayItem).concat([newArrayItem])
                    

                    如果您的数组包含对象,您可以像这样调整过滤器功能:

                    someArray.filter(f => f.some(s => s.id === myId)).concat([{ id: myId }])
                    

                    【讨论】:

                    • 这里是一个非常优雅的解决方案。谢谢!
                    【解决方案20】:

                    您可以将 findIndex 方法与回调函数及其“this”参数一起使用。

                    注意:旧浏览器不知道 findIndex,但可以使用 polyfill。

                    示例代码(请注意,在原始问题中,仅当新对象的数据均不在先前推送的对象中时才会推送新对象):

                    var a=[{name:"tom", text:"tasty"}], b;
                    var magic=function(e) {
                        return ((e.name == this.name) || (e.text == this.text));
                    };
                    
                    b={name:"tom", text:"tasty"};
                    if (a.findIndex(magic,b) == -1)
                        a.push(b); // nothing done
                    b={name:"tom", text:"ugly"};
                    if (a.findIndex(magic,b) == -1)
                        a.push(b); // nothing done
                    b={name:"bob", text:"tasty"};
                    if (a.findIndex(magic,b) == -1)
                        a.push(b); // nothing done
                    b={name:"bob", text:"ugly"};
                    if (a.findIndex(magic,b) == -1)
                        a.push(b); // b is pushed into a
                    

                    【讨论】:

                      【解决方案21】:

                      当您希望通过对象的特定属性进行搜索时,我使用 map 和 reduce 来执行此操作,这很有用,因为直接进行对象相等通常会失败。

                      var newItem = {'unique_id': 123};
                      var searchList = [{'unique_id' : 123}, {'unique_id' : 456}];
                      
                      hasDuplicate = searchList
                         .map(function(e){return e.unique_id== newItem.unique_id})
                         .reduce(function(pre, cur) {return pre || cur});
                      
                      if (hasDuplicate) {
                         searchList.push(newItem);
                      } else {
                         console.log("Duplicate Item");
                      }
                      

                      【讨论】:

                        【解决方案22】:

                        您可以使用 foreach 检查数组,如果存在则弹出该项目,否则添加新项目...

                        示例 newItemValue &submitFields 是键值对

                        > //submitFields existing array
                        >      angular.forEach(submitFields, function(item) {
                        >                   index++; //newItemValue new key,value to check
                        >                     if (newItemValue == item.value) {
                        >                       submitFields.splice(index-1,1);
                        >                         
                        >                     } });
                        
                                        submitFields.push({"field":field,"value":value});
                        

                        【讨论】:

                          【解决方案23】:

                          如果您需要一些简单的东西而不想扩展 Array 原型:

                          // Example array
                          var array = [{id: 1}, {id: 2}, {id: 3}];
                          
                          function pushIfNew(obj) {
                            for (var i = 0; i < array.length; i++) {
                              if (array[i].id === obj.id) { // modify whatever property you need
                                return;
                              }
                            }
                            array.push(obj);
                          }
                          

                          【讨论】:

                            【解决方案24】:

                            您可以使用自定义方法扩展 Array 原型:

                            // check if an element exists in array using a comparer function
                            // comparer : function(currentElement)
                            Array.prototype.inArray = function(comparer) { 
                                for(var i=0; i < this.length; i++) { 
                                    if(comparer(this[i])) return true; 
                                }
                                return false; 
                            }; 
                            
                            // adds an element to the array if it does not already exist using a comparer 
                            // function
                            Array.prototype.pushIfNotExist = function(element, comparer) { 
                                if (!this.inArray(comparer)) {
                                    this.push(element);
                                }
                            }; 
                            
                            var array = [{ name: "tom", text: "tasty" }];
                            var element = { name: "tom", text: "tasty" };
                            array.pushIfNotExist(element, function(e) { 
                                return e.name === element.name && e.text === element.text; 
                            });
                            

                            【讨论】:

                            • 我认为你的camparer(比较器?)应该有两个参数,这将简化当附加值是内联而不是你可以在函数中访问的变量时的情况。 array.pushIfNotExist({ name: "tom", text: "tasty" }, function(a,b){ return a.name === b.name && a.text === b.text; });
                            • 我想知道为什么这不是语言原生的——忘记它是如何实现的——“仅在唯一时添加”的想法是如此基本以至于被假定存在。
                            • 最好用 JavaScript 1.6 方法 IndexOf 来扩展 Array 原型,而不是你的 inArray。
                            • Array.findIndex() 是一个内置的 JS 函数,可以实现与您的代码相同的功能。
                            • 直接扩展内置对象是一种不好的做法。
                            【解决方案25】:

                            正是出于这些原因,使用像 underscore.js 这样的 js 库。用途: union:计算传入数组的并集:按顺序排列在一个或多个数组中的唯一项的列表。

                            _.union([1, 2, 3], [101, 2, 1, 10], [2, 1]);
                            => [1, 2, 3, 101, 10]
                            

                            【讨论】:

                            • 注意,这会返回一个新数组,实际上并不推送到现有数组。
                            • 恕我直言,真的没有必要引入一个框架来测试这么简单的东西
                            【解决方案26】:

                            如果没有结果,您可以使用 jQuery grep 并推送:http://api.jquery.com/jQuery.grep/

                            它与“扩展原型”的解决方案基本相同,但没有扩展(或污染)原型。

                            【讨论】:

                              【解决方案27】:

                              http://api.jquery.com/jQuery.unique/

                              var cleanArray = $.unique(clutteredArray);
                              

                              你可能也对 makeArray 感兴趣

                              前面的例子最好说在push之前检查它是否存在。 事后看来,它还声明您可以将其声明为原型的一部分(我猜这就是类扩展),因此下面没有大的增强。

                              除非我不确定 indexOf 是否比 inArray 更快?大概吧。

                              Array.prototype.pushUnique = function (item){
                                  if(this.indexOf(item) == -1) {
                                  //if(jQuery.inArray(item, this) == -1) {
                                      this.push(item);
                                      return true;
                                  }
                                  return false;
                              }
                              

                              【讨论】:

                              • 来自 jQuery 链接:Note that this only works on arrays of DOM elements, not strings or numbers. 另外,indexOf 在 IE8 中不起作用 :(
                              • 你可以使用 lodash _.indexOf,它可以在 IE8 中使用
                              猜你喜欢
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              • 2017-12-15
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              相关资源
                              最近更新 更多