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"หรือtext: "tasty"ฉันไม่ต้องการให้เกิดอะไรขึ้น ... แต่ถ้าไม่มีสิ่งเหล่านั้นฉันก็อยากให้มัน.push()

ฉันจะทำสิ่งนี้ได้อย่างไร


5
ใช้พจนานุกรม (แฮช / ทรี) แทนอาร์เรย์
โทมัส Eding

สิ่งเหล่านี้มีอยู่ในจาวาสคริปต์หรือไม่
ราหุล


3
ใช้Set
Drax

1
ชุดใช้ไม่ได้กับอาร์เรย์ของวัตถุ
rffaguiar

คำตอบ:


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 ของคุณ (comparator?) ควรใช้อาร์กิวเมนต์สองตัวซึ่งจะทำให้กรณีนี้ง่ายขึ้นเมื่อค่าที่เพิ่มเข้ามาเป็นแบบอินไลน์และไม่อยู่ในตัวแปรที่คุณสามารถเข้าถึงได้ในฟังก์ชันของคุณ array.pushIfNotExist ({ชื่อ: "ทอม", ข้อความ: "เทสตี้"}, ฟังก์ชั่น (a, b) {return a.name === b.name && a.text === b.text;});
Vincent Robert

26
ฉันสงสัยว่าทำไมสิ่งนี้ไม่ได้เกิดจากภาษา - ลืมวิธีการนำไปใช้ - ความคิดในการ 'เพิ่มเฉพาะในกรณีที่ไม่ซ้ำกัน' นั้นเป็นพื้นฐานที่จะถือว่ามีอยู่จริง
justSteve

9
มันเป็นการดีกว่าที่จะขยาย Array prototype ด้วยวิธี JavaScript 1.6 IndexOf แทน inArray ของคุณ
Eugene Gluhotorenko

7
Array.findIndex()เป็นฟังก์ชั่น JS ในตัวที่จะได้ผลเหมือนกับรหัสของคุณ

4
การขยายวัตถุในตัวโดยตรงเป็นการปฏิบัติที่ไม่ดี
Slava Fomin II

429

สำหรับอาเรย์ของสตริง (แต่ไม่ใช่อาเรย์ของออบเจ็กต์) คุณสามารถตรวจสอบว่ามีไอเท็มอยู่โดยการเรียกใช้หรือไม่.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
ไม่แน่ใจว่าทำไมจึงไม่ถูกตั้งค่าสถานะว่าถูกต้อง ไม่ใช้ภายนอกใด ๆ ไม่ต้องการสร้างส่วนขยายและตายง่าย คำตอบที่สมบูรณ์แบบสำหรับคำถาม ops
pimbrouwers

39
ในคำถามแรกค่าของอาเรย์เป็นออบเจ็กต์ไม่ใช่สตริ (และวิธีนี้ไม่ทำงานเหมือนว่าค่าเป็นออบเจ็กต์)
Simon Hi

12
@EmilPedersen - ไม่ได้จริงๆ ลองif (a.indexOf({ name: "tom", text: "tasty" })!=-1) a.push({ name: "tom", text: "tasty" })สองครั้ง มันจะเพิ่มวัตถุ 'ที่คล้ายกัน' สองครั้ง
commonpike

18
คำตอบนี้ควรถูกลบออกเนื่องจากมันผิดอย่างเป็นรูปธรรม แต่ก็ยังดึงดูดผู้โหวตมากที่สุด
นิโคลา

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
นี่คือคำตอบพวก !!
jafed

2
ส่วนใหญ่เกี่ยวข้องกับการเพิ่มองค์ประกอบในอาร์เรย์ถ้าไม่มี
akshay bagade

1
ขอบคุณกำลังมองหาสิ่งนี้ทุกที่
dt192

41

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

var cleanArray = $.unique(clutteredArray);

คุณอาจสนใจใน makeArray ด้วย

ตัวอย่างก่อนหน้านี้ดีที่สุดในการบอกว่าตรวจสอบว่ามันมีอยู่ก่อนที่จะผลักดัน ฉันเห็นว่ามันสามารถเข้าใจได้ว่ามันเป็นส่วนหนึ่งของต้นแบบ (ฉันเดาว่านั่นคือส่วนขยายคลาส) ดังนั้นจึงไม่มีการปรับปรุงที่ดีด้านล่าง

ยกเว้นฉันไม่แน่ใจว่า indexOf เป็นเส้นทางที่เร็วกว่าหรือไม่แล้วใน Array อาจ.

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

ใช้ไลบรารี js เช่นunderscore.jsด้วยเหตุผลเหล่านี้ ใช้: union: คำนวณยูเนี่ยนของอาร์เรย์ที่ส่งผ่าน: รายการของรายการที่ไม่ซ้ำตามลำดับที่มีอยู่ในหนึ่งหรือหลายอาร์เรย์

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

8
หมายเหตุนี่จะส่งคืนอาร์เรย์ใหม่และจะไม่ส่งไปยังอาร์เรย์ที่มีอยู่จริง
ilovett

4
IMHO ไม่จำเป็นต้องนำเฟรมเวิร์กมาทำการทดสอบกับบางสิ่งที่ง่ายดังนั้น
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 "find" หยุดหลังจากที่พบรายการ
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
นี่เป็นคำตอบที่สง่างาม ขอบคุณ!
Jonathan Picazo

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

ฉันขอแนะนำให้คุณใช้ชุด ,

ชุดอนุญาตเฉพาะรายการที่ไม่ซ้ำกันซึ่งจะแก้ปัญหาของคุณโดยอัตโนมัติ

ชุดสามารถประกาศได้เช่น:

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

ขอบคุณสำหรับการชี้ให้เห็นว่า @Michael ทางออกที่ดีสำหรับเมื่อเราต้องการรักษาข้อมูลที่แตกต่างด้วยความพยายามขั้นต่ำ FWIW เป็นสิ่งสำคัญที่จะต้องทราบว่าประสิทธิภาพของอาเรย์นั้นดีกว่าเนื่องจากต้องการ CPU ที่น้อยกว่าในการดึงข้อมูลองค์ประกอบเมื่อจำเป็น
Ben

คำถามถามเกี่ยวกับArray.pushดังนั้นจึงSet.addเท่ากับ
bryc

9

โค้ดง่าย ๆ ถ้า 'indexOf' ส่งคืน '-1' หมายความว่าองค์ประกอบนั้นไม่ได้อยู่ในอาร์เรย์ดังนั้นเงื่อนไข '=== -1' จะเรียกข้อมูลจริง / เท็จ

ตัวดำเนินการ '&&' หมายถึง 'และ' ดังนั้นหากเงื่อนไขแรกเป็นจริงเราจะส่งมันไปยังอาร์เรย์

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

@ D.Lawrence ใช่ดีกว่ามากตอนนี้
Eric Valero

มีคำตอบอื่น ๆ ที่ได้รับการยอมรับซึ่งให้คำถามของ 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);
    }
};

อัปเดต: แทนที่ indexOf และตัดขอบด้วยทางเลือก jQuery สำหรับความเข้ากันได้ของ IE8


มันเป็นคำตอบที่ดี แต่ทำไมถึงใช้ trim?
Dejan Dozet

2

ฉันใช้แผนที่และลดการทำเช่นนี้ในกรณีที่คุณต้องการค้นหาด้วยคุณสมบัติเฉพาะของวัตถุมีประโยชน์ในการทำความเสมอภาคของวัตถุโดยตรงมักจะล้มเหลว

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
ไม่ถูกต้อง. เราไม่ได้สนใจที่จะผลักดันกุญแจเราต้องการที่จะผลักดันคู่ค่าชื่อ แต่ถ้ามันไม่ได้มีอยู่แล้ว
Stefan

2

a คืออาร์เรย์ของวัตถุที่คุณมี

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

1

คุณสามารถใช้วิธี findIndex ด้วยฟังก์ชันการเรียกกลับและพารามิเตอร์ "this"

หมายเหตุ: เบราว์เซอร์เก่าไม่รู้จัก findIndex แต่มีโพลีฟิลล์

โค้ดตัวอย่าง (โปรดระวังว่าในคำถามเดิมวัตถุใหม่จะถูกพุชก็ต่อเมื่อไม่มีข้อมูลใด ๆ อยู่ในออบเจ็กต์ที่ถูกบีบอัดแบบ previoulsy):

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

นี่คือการทำงาน func สำหรับการเปรียบเทียบวัตถุ ในบางกรณีคุณอาจมีเขตข้อมูลจำนวนมากที่จะเปรียบเทียบ เพียงแค่วนรอบอาร์เรย์และเรียกใช้ฟังก์ชันนี้ด้วยรายการที่มีอยู่และรายการใหม่

 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]

-1

คุณสามารถใช้ jQuery grep และพุชหากไม่มีผลลัพธ์: http://api.jquery.com/jQuery.grep/

โดยพื้นฐานแล้วมันเป็นโซลูชันเดียวกับในโซลูชัน "การขยายต้นแบบ" แต่ไม่มีการขยายต้นแบบ (หรือก่อให้เกิดมลพิษ)


-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});
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.