Array.push () nếu không tồn tại?


247

Làm thế nào tôi có thể đẩy vào một mảng nếu không có giá trị nào tồn tại? Đây là mảng của tôi:

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

Nếu tôi cố gắng đẩy lại vào mảng với một trong hai name: "tom" hoặc text: "tasty", tôi không muốn bất cứ điều gì xảy ra ... nhưng nếu không ai trong số những người đang có sau đó tôi muốn nó.push()

Tôi có thể làm cái này như thế nào?


5
Sử dụng một từ điển (băm / cây) thay vì một mảng.
Thomas Eding

Có phải tất cả những thứ này có sẵn trong javascript?
rahul


3
sử dụng Set
Drax

1
Set không hoạt động với mảng các đối tượng
rffaguiar

Câu trả lời:


114

Bạn có thể mở rộng nguyên mẫu Array bằng một phương thức tùy chỉnh:

// 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
Tôi nghĩ rằng camparer của bạn (bộ so sánh?) Nên có hai đối số, điều này sẽ đơn giản hóa trường hợp khi giá trị gia tăng là nội tuyến và không phải là một biến bạn có thể truy cập trong hàm của mình. mảng.push IfNotExist ({name: "tom", văn bản: "ngon"}, hàm (a, b) {return a.name === b.name && a.text === b.text;});
Vincent Robert

26
Tôi tự hỏi tại sao điều này không có nguồn gốc từ ngôn ngữ - hãy quên cách nó được triển khai - ý tưởng "chỉ thêm nếu duy nhất" là cơ bản đến mức được giả sử tồn tại.
justSteve

9
Tốt hơn là mở rộng nguyên mẫu Array bằng phương pháp JavaScript 1.6 IndexOf thay vì inArray của bạn.
Eugene Gluhotorenko

7
Array.findIndex()là một hàm JS tích hợp sẽ đạt được giống như mã của bạn.

4
Mở rộng các đối tượng tích hợp trực tiếp là một thực tế xấu.
Slava Fomin II

429

Đối với một chuỗi các chuỗi (nhưng không phải là một mảng các đối tượng), bạn có thể kiểm tra xem một mục có tồn tại hay không bằng cách gọi .indexOf()và nếu không thì chỉ cần đẩy mục đó vào mảng:

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
Không chắc chắn tại sao điều này không được gắn cờ là chính xác. Nó không sử dụng bất kỳ phần bên ngoài nào, không yêu cầu tạo phần mở rộng và rất đơn giản. Câu trả lời hoàn hảo cho câu hỏi ops.
pimbrouwers

39
Trong câu hỏi ban đầu, các giá trị của mảng là các đối tượng, không phải các chuỗi (và giải pháp này không hoạt động như thể nếu các giá trị là các đối tượng).
Simon Hi

12
@EmilPedersen - không thực sự. Hãy thử if (a.indexOf({ name: "tom", text: "tasty" })!=-1) a.push({ name: "tom", text: "tasty" })hai lần. Nó sẽ thêm một đối tượng 'tương tự' hai lần.
phổ biến

18
Câu trả lời này nên được loại bỏ vì nó sai khách quan, nhưng vẫn thu hút số lượng upvote cao nhất.
nikola

2
Đây không phải là một câu trả lời đúng, tại sao được chấp nhận? Nó chỉ hoạt động với mảng Js, không phải đối tượng trong mảng.
Digitai

100

Nó khá dễ thực hiện khi sử dụng Array.findIndexhàm, trong đó lấy một hàm làm đối số:

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
Đây là câu trả lời các bạn ạ !!
lừa

2
Liên quan nhất để thêm một phần tử trong mảng nếu không có mặt
akshay bagade 31/03/19

1
Cảm ơn, đã tìm kiếm điều này ở khắp mọi nơi.
dt192

41

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

var cleanArray = $.unique(clutteredArray);

bạn cũng có thể quan tâm đến makeArray

Ví dụ trước là tốt nhất khi nói rằng kiểm tra nếu nó tồn tại trước khi đẩy. Tôi thấy trong nhận thức muộn, nó cũng nói rằng bạn có thể khai báo nó như là một phần của nguyên mẫu (tôi đoán đó là Phần mở rộng Class), vì vậy không có sự cải tiến lớn nào dưới đây.

Ngoại trừ tôi không chắc nếu indexOf là tuyến nhanh hơn thì inArray? có lẽ.

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

22
Từ liên kết jQuery: Note that this only works on arrays of DOM elements, not strings or numbers.Ngoài ra, indexOf không hoạt động trong IE8 :(
dmathisen

Bạn có thể sử dụng lodash _.indexOf, nó sẽ hoạt động trong IE8
LTroya

25

Sử dụng thư viện js như underscore.js vì những lý do này chính xác. Sử dụng: union: Tính toán sự kết hợp của các mảng đã qua: danh sách các mục duy nhất, theo thứ tự, có trong một hoặc nhiều mảng.

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

8
Lưu ý, điều này trả về một mảng mới và không thực sự đẩy đến một mảng hiện có.
ilovett

4
IMHO thực sự không cần phải đưa ra một khuôn khổ để kiểm tra một cái gì đó quá đơn giản
DrewT

24

Như thế này?

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

Với đối tượng

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

4
array.findlà một ý tưởng tồi bởi vì nó tìm kiếm toàn bộ mảng. Sử dụng findIndex, chỉ tìm kiếm cho đến khi xuất hiện đầu tiên.

3
@ K48 theo điều này: stackoverflow.com/a/33759573/5227365 "tìm" dừng sau khi tìm thấy mục
Pascal

19

Tôi biết đây là một câu hỏi rất cũ, nhưng nếu bạn đang sử dụng ES6, bạn có thể sử dụng một phiên bản rất nhỏ:

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

Rất dễ dàng, lúc đầu, thêm một bộ lọc loại bỏ vật phẩm - nếu nó đã tồn tại, sau đó thêm nó thông qua một concat.

Đây là một ví dụ thực tế hơn:

const myArray = ['hello', 'world']
const newArrayItem

myArray.filter(f => f !== newArrayItem).concat([newArrayItem])

Nếu mảng của bạn chứa các đối tượng, bạn có thể điều chỉnh chức năng lọc như thế này:

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

3
Khá là một giải pháp thanh lịch ở đây. Cảm ơn!
Jonathan Picazo

18

Đẩy mạnh

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

Trong phương pháp đơn giản

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

Nếu mảng chỉ chứa các kiểu nguyên thủy / mảng đơn giản

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

2
Sức khỏe đến tay của bạn. Giải pháp đơn giản và đẹp mắt @Gopala raja naika
Nasimba

11

Tôi sẽ đề nghị bạn sử dụng một Set ,

Bộ chỉ cho phép các mục duy nhất, tự động giải quyết vấn đề của bạn.

Các bộ có thể được khai báo như vậy:

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

Cảm ơn đã chỉ ra rằng @Michael. Giải pháp tốt khi chúng tôi muốn duy trì dữ liệu riêng biệt với nỗ lực tối thiểu. FWIW, điều quan trọng cần lưu ý là hiệu suất mảng tốt hơn vì nó yêu cầu ít CPU hơn để tìm nạp phần tử khi cần.
Ben

Câu hỏi hỏi về Array.push, vì vậy Set.addlà tương đương với điều đó.
bryc

9

Mã dễ dàng, nếu 'indexOf' trả về '-1', điều đó có nghĩa là phần tử đó không nằm trong mảng thì điều kiện '=== -1' lấy đúng / sai.

Toán tử '&&' có nghĩa là 'và', vì vậy nếu điều kiện đầu tiên là đúng, chúng ta sẽ đẩy nó vào mảng.

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

@ D.Lawrence Vâng, bây giờ tốt hơn nhiều.
Eric Valero

Có những câu trả lời được chấp nhận khác cung cấp câu hỏi của OP và chúng đã được đăng cách đây một thời gian. Khi đăng một câu trả lời xem: Làm thế nào để tôi viết một câu trả lời tốt? , vui lòng đảm bảo bạn thêm một giải pháp mới hoặc giải thích rõ ràng hơn, đặc biệt là khi trả lời các câu hỏi cũ hơn.
help-info.de

4

Không chắc chắn về tốc độ, nhưng stringification+ indexOflà một cách tiếp cận đơn giản. Bắt đầu với việc biến mảng của bạn thành một chuỗi:

let strMyArray = JSON.stringify(myArray);

Sau đó, cho một loạt các cặp giá trị thuộc tính, bạn có thể sử dụng:

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

Tìm một đối tượng toàn bộ đơn giản hơn:

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

3

Trong trường hợp bạn cần một cái gì đó đơn giản mà không muốn mở rộng nguyên mẫu 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

Trong trường hợp bất kỳ ai có các yêu cầu ít phức tạp hơn, đây là phần điều chỉnh câu trả lời của tôi cho một chuỗi chuỗi đơn giản:

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

Cập nhật: Đã thay thế indexOf và cắt bằng các lựa chọn thay thế jQuery cho khả năng tương thích IE8


nó là một giải pháp tốt, nhưng tại sao lại sử dụng trim?
Dejan Dozet

2

Tôi đã sử dụng bản đồ và rút gọn để làm điều này trong trường hợp bạn muốn tìm kiếm theo một thuộc tính cụ thể của một đối tượng, hữu ích vì thực hiện bình đẳng đối tượng trực tiếp thường sẽ thất bại.

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

Ví dụ ngắn:

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

1
Không chính xác. Chúng tôi không quan tâm đến việc đẩy khóa, chúng tôi muốn đẩy một cặp tên-giá trị, nhưng chỉ khi nó chưa tồn tại.
Stefan

2

a là mảng các đối tượng bạn có

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

1

Bạn có thể sử dụng phương thức find Index với hàm gọi lại và tham số "this" của nó.

Lưu ý: các trình duyệt cũ không biết find Index nhưng có sẵn một polyfill.

Mã mẫu (lưu ý rằng trong câu hỏi ban đầu, một đối tượng mới chỉ được đẩy nếu cả hai dữ liệu của nó không nằm trong các đối tượng bị đẩy tiền tâm lý):

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

Tôi đoán rằng tôi đã quá muộn để trả lời ở đây tuy nhiên đây là những gì cuối cùng tôi đã nghĩ ra cho một trình quản lý thư tôi đã viết. Công trình đó là tất cả những gì tôi cần.

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

Đây là func làm việc để so sánh các đối tượng. Trong một số trường hợp, bạn có thể có nhiều lĩnh vực để so sánh. Đơn giản chỉ cần lặp mảng và gọi hàm này với một mục hiện có và mục mới.

 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

Ở đây bạn có một cách để làm điều đó trong một dòng cho hai mảng:

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]

-1

Bạn có thể sử dụng jQuery grep và đẩy nếu không có kết quả: http://api.jquery.com/jQuery.grep/

Về cơ bản, đây là giải pháp tương tự như trong giải pháp "mở rộng nguyên mẫu", nhưng không mở rộng (hoặc gây ô nhiễm) nguyên mẫu.


-2

Bạn có thể kiểm tra mảng bằng cách sử dụng foreach và sau đó bật mục nếu nó tồn tại nếu không thêm mục mới ...

mẫu newItemValue & submitFields là các cặp khóa, giá trị

> //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});
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.