Array.push()如果不存在?


247

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

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

如果我尝试使用name: "tom"or或再次将其推入数组text: "tasty",我什么都不想发生...但是如果这两个都不存在,那么我希望它.push()

我怎样才能做到这一点?


5
使用字典(哈希/树)而不是数组。
Thomas Eding

所有这些都可以在javascript中使用吗?
rahul 2010年


3
使用套装
Drax

1
Set不适用于对象数组
rffaguiar,

Answers:


114

您可以使用自定义方法扩展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; 
});

5
我认为您的Camparer(比较器?)应使用两个参数,当添加的值是内联而不是可以在函数中访问的变量中时,这将简化这种情况。array.pushIfNotExist({name:“ tom”,text:“ tasty”},function(a,b){return a.name === b.name && a.text === b.text;});
文森特·罗伯特,2010年

26
我想知道为什么这不是该语言的本机-忘记了它是如何实现的-“只有在唯一时才添加”的想法是如此基础,以至于被认为存在。
justSteve 2011年

9
最好使用JavaScript 1.6方法IndexOf而不是inArray扩展Array原型。
Eugene Gluhotorenko

7
Array.findIndex()是内置的JS函数,可以实现与代码相同的功能。

4
直接扩展内置对象是一种不好的做法。
Slava Fomin II

428

对于字符串数组(而不是对象数组),您可以通过调用检查某项是否存在.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)


50
不确定为什么未将其标记为正确。它不使用任何外部组件,不需要创建扩展名,而且非常简单。操作问题的完美答案。
pimbrouwers

39
在最初的问题中,数组的值是对象,而不是字符串(如果值是对象,此解决方案将无法正常工作)。
西蒙嗨

12
@EmilPedersen-并非如此。尝试if (a.indexOf({ name: "tom", text: "tasty" })!=-1) a.push({ name: "tom", text: "tasty" })两次。它将添加两次“相似”对象。
commonpike

18
应该删除此答案,因为它是客观上的错误,但仍吸引了最多的支持。
尼古拉'17

2
这不是正确答案,为什么会被接受?它仅适用于Js数组,而不适用于数组中的对象。
digitai

100

使用该Array.findIndex函数非常容易,该函数接受一个函数作为参数:

var a = [{name:"bull", text: "sour"},
    { name: "tom", text: "tasty" },
    { name: "tom", text: "tasty" }
]
var index = a.findIndex(x => x.name=="bob")
// here you can check specific property for an object whether it exist in your array or not

if (index === -1){
    a.push({your_object});
}
else console.log("object already exists")

8
这就是答案!!
激怒

2
最相关的是在数组中添加元素(如果不存在的话)
akshay bagade'Mar

1
谢谢,一直在寻找这个。
dt192

41

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

var cleanArray = $.unique(clutteredArray);

您可能也对makeArray感兴趣

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

除非我不确定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;
}

22
从jQuery链接:Note that this only works on arrays of DOM elements, not strings or numbers.此外,indexOf在IE8中不起作用:(
dmathisen

您可以使用lodash _.indexOf,它将在IE8
LTroya

25

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

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

8
请注意,这将返回一个新数组,并且实际上不会推送到现有数组。
ilovett

4
恕我直言,实际上没有必要引入框架来测试如此简单的东西
DrewT

24

像这样?

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)

4
array.find这是一个坏主意,因为它会搜索整个数组。使用findIndex,仅搜索直到第一次出现。

3
@ K48据此:stackoverflow.com/a/33759573/5227365找到该项目后停止“查找”
Pascal,

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 }])

3
这里是一个很好的解决方案。谢谢!
乔纳森·皮卡佐

18

动态推送

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);

2
双手健康。简单美观的解决方案@Gopala raja naika
Nasimba

11

我建议您使用Set

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

可以这样声明集合:

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

感谢您指出@Michael。当我们想要以最小的努力维护不同的数据时的好解决方案。FWIW,必须注意,阵列性能更好,因为在需要时可以用更少的CPU来提取元素。

问题问有关Array.push,所以Set.add等价于此。
bryc

9

简单的代码,如果'indexOf'返回'-1',则表示元素不在数组内,则条件'=== -1'检索true / false。

“ &&”运算符的意思是“ and”,因此如果第一个条件为true,则将其推入数组。

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

@ D.Lawrence是的,现在好多了。
埃里克·瓦莱罗

还有其他可接受的答案提供了OP的问题,并且它们是在一段时间前发布的。发布答案时,请参阅:如何写一个好的答案?,请确保您添加了新的解决方案或实质上更好的解释,尤其是在回答较旧的问题时。
help-info.de

4

不确定速度,但是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);
}

3

如果您需要简单的东西而又不想扩展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);
}

3

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

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

更新:用jQuery替代品的indexOf和trim替代了IE8的兼容性


这是一个不错的解决方案,但是为什么要使用修剪?
Dejan Dozet '19

2

在希望按对象的特定属性进行搜索的情况下,我使用了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");
}

2

简短示例:

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

1
不正确。我们对推送键不感兴趣,我们希望推送名称-值对,但前提是它不存在。
斯特凡

2

a是您拥有的对象数组

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

1

您可以将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

1

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

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>


0

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

 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;
    };

0

在这里,您有一种方法可以针对两个数组在一行中完成此操作:

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]


-2

您可以使用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});
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.