Javascript ES6 / ES5 ค้นหาในอาร์เรย์และการเปลี่ยนแปลง


134

ฉันมีอาร์เรย์ของวัตถุ ฉันต้องการค้นหาตามฟิลด์บางฟิลด์จากนั้นจึงเปลี่ยน:

var item = {...}
var items = [{id:2}, {id:2}, {id:2}];

var foundItem = items.find(x => x.id == item.id);
foundItem = item;

ฉันต้องการให้มันเปลี่ยนวัตถุเดิม อย่างไร? (ฉันไม่สนหรอกว่ามันจะอยู่ใน lodash ด้วยหรือเปล่า)


Dose วัตถุใหม่ของคุณitemมีidคีย์หรือไม่ หรือคุณคิดว่าจะมี id ตลอดจนคุณสมบัติทั้งหมดจากitemobject ในรายการอาร์เรย์
Koushik Chatterjee

คำตอบ:


253

คุณสามารถใช้findIndexเพื่อค้นหาดัชนีในอาร์เรย์ของวัตถุและแทนที่ได้ตามต้องการ:

var item = {...}
var items = [{id:2}, {id:2}, {id:2}];

var foundIndex = items.findIndex(x => x.id == item.id);
items[foundIndex] = item;

สิ่งนี้ถือว่า ID ที่ไม่ซ้ำกัน หากรหัสของคุณซ้ำกัน (ตามตัวอย่าง) อาจดีกว่าถ้าคุณใช้ forEach:

items.forEach((element, index) => {
    if(element.id === item.id) {
        items[index] = item;
    }
});

16
@georg นั่นจะส่งคืนอาร์เรย์ใหม่
CodingIntrigue

3
ฟังก์ชัน => จะไม่ทำงานใน IE11 โดนกัดเมื่อเร็ว ๆ นี้.
Lewis Cianci

1
อาจจะเป็นการดีกว่าถ้าใช้letคำหลักแทนvar
Inus Saha

เพียงแค่ FYI สิ่งนี้ใช้ไม่ได้กับ phantomJS บางเวอร์ชัน
Sid

1
ฉันชอบวิธีการ verbose มากกว่าที่ @CodingIntrigue ใช้แทนที่จะใช้ซับเดียวmapที่ @georg ใช้ ต้องใช้ยิมนาสติกน้อยในการคิดว่าเกิดอะไรขึ้น คุ้มค่ากับรหัสพิเศษ
Joshua Pinter

44

แนวทางที่ดีที่สุดของฉันคือ:

var item = {...}
var items = [{id:2}, {id:2}, {id:2}];

items[items.findIndex(el => el.id === item.id)] = item;

ข้อมูลอ้างอิงสำหรับfindIndex

และในกรณีที่คุณไม่ต้องการแทนที่ด้วย object ใหม่ แต่itemคุณสามารถใช้Object.assign:

Object.assign(items[items.findIndex(el => el.id === item.id)], item)

เป็นอีกทางเลือกหนึ่งด้วย.map():

Object.assign(items, items.map(el => el.id === item.id? item : el))

แนวทางการทำงาน :

อย่าแก้ไขอาร์เรย์ใช้อาร์เรย์ใหม่ดังนั้นคุณจะไม่สร้างผลข้างเคียง

const updatedItems = items.map(el => el.id === item.id ? item : el)

1
โปรดเชื่อมโยงไปยังหน้าภาษาอังกฤษหากคำถามเดิมเป็นภาษาอังกฤษ นอกจากนี้ตัวอย่างนี้ถือว่าพบวัตถุเสมอ
raarts

1
คุณสามารถห่อด้วยนิพจน์ try catch ได้เสมอ ... ใช่ไหม?
Soldeplata Saketos

1
เขาต้องการแก้ไของค์ประกอบในอาร์เรย์ เขาไม่ต้องการรู้ว่ามันมีอยู่จริงหรือไม่ดังนั้นเราจึงถือว่าเขาทำแบบนั้นมาก่อนแล้ว
Soldeplata Saketos

@SoldeplataSaketos ใช่คุณสามารถห่อเป็น a try/catchได้ แต่คุณไม่ควรเพราะการไม่พบองค์ประกอบไม่ใช่กรณีพิเศษ เป็นกรณีมาตรฐานที่คุณควรพิจารณาโดยการตรวจสอบค่าส่งคืนจากfindIndexนั้นอัปเดตอาร์เรย์เมื่อพบองค์ประกอบเท่านั้น
Wayne

20

วิธีการอื่น ๆ คือการใช้ประกบกัน

splice()วิธีการเปลี่ยนแปลงเนื้อหาของอาร์เรย์โดยการลบหรือเปลี่ยนองค์ประกอบที่มีอยู่และ / หรือการเพิ่มองค์ประกอบใหม่ในสถานที่

หมายเหตุ:ในกรณีที่คุณกำลังทำงานกับเฟรมเวิร์กแบบรีแอกทีฟมันจะอัปเดต "มุมมอง" อาร์เรย์ของคุณ "รู้" ว่าคุณได้อัปเดตแล้ว

คำตอบ:

var item = {...}
var items = [{id:2}, {id:2}, {id:2}];

let foundIndex = items.findIndex(element => element.id === item.id)
items.splice(foundIndex, 1, item)

และในกรณีที่คุณต้องการเปลี่ยนเฉพาะค่าของรายการคุณสามารถใช้ฟังก์ชันค้นหา :

// Retrieve item and assign ref to updatedItem
let updatedItem = items.find((element) => { return element.id === item.id })

// Modify object property
updatedItem.aProp = ds.aProp

15

รับวัตถุที่เปลี่ยนแปลงและอาร์เรย์:

const item = {...}
let items = [{id:2}, {id:3}, {id:4}];

อัปเดตอาร์เรย์ด้วยออบเจ็กต์ใหม่โดยทำซ้ำบนอาร์เรย์:

items = items.map(x => (x.id === item.id) ? item : x)

กรุณาอย่าเพิ่งวางโค้ด อธิบายสิ่งที่กำลังทำและวิธีการแก้ปัญหา
Spencer

1
ฉันคิดว่านี่เป็นทางออกที่ดีที่สุดเนื่องจากมีประสิทธิภาพที่ดีที่สุดเนื่องจากผ่านอาร์เรย์เพียงครั้งเดียวและเปลี่ยนการอ้างอิงของอาร์เรย์ดังนั้นจึงจะหลีกเลี่ยงสถานการณ์ที่ไม่แน่นอน
Ohad Sadan

6

อาจจะใช้ตัวกรอง

const list = [{id:0}, {id:1}, {id:2}];
let listCopy = [...list];
let filteredDataSource = listCopy.filter((item) => {
       if (item.id === 1) {
           item.id = 12345;
        }

        return item;
    });
console.log(filteredDataSource);

อาร์เรย์ [Object {id: 0}, Object {id: 12345}, Object {id: 2}]


ฉันชอบตัวกรองเพราะอนุญาตให้สร้างอาร์เรย์ใหม่และสำหรับสิ่งนี้ยังไม่มีรายการที่มีอยู่จะถูก 'ลบ'
pungggi

0

ทำงานให้ฉัน

let returnPayments = [ ...this.payments ];

returnPayments[this.payments.findIndex(x => x.id == this.payment.id)] = this.payment;

1
กรุณาอย่าเพิ่งวางโค้ด อธิบายสิ่งที่กำลังทำและวิธีการแก้ปัญหา
Adrian Mole

คำตอบที่ได้รับการโหวตมากที่สุดที่ได้รับการยอมรับนั้นไม่แตกต่างกันมากนัก แต่คุณไม่ได้ชี้ให้พวกเขาอัปเดตคำตอบที่นั่น .. ทำไมถึงเป็นเช่นนั้น?
li x

0

ในขณะที่คำตอบที่มีอยู่ส่วนใหญ่นั้นยอดเยี่ยมฉันต้องการรวมคำตอบโดยใช้แบบดั้งเดิมสำหรับลูปซึ่งควรพิจารณาที่นี่ด้วย OP ขอคำตอบที่เข้ากันได้กับ ES5 / ES6 และใช้แบบดั้งเดิมสำหรับลูป :)

ปัญหาในการใช้ฟังก์ชันอาร์เรย์ในสถานการณ์นี้คือพวกเขาไม่ได้กลายพันธุ์วัตถุ แต่ในกรณีนี้การกลายพันธุ์เป็นข้อกำหนด ประสิทธิภาพที่เพิ่มขึ้นจากการใช้แบบดั้งเดิมสำหรับลูปเป็นเพียงโบนัส (มหาศาล)

const findThis = 2;
const items = [{id:1, ...}, {id:2, ...}, {id:3, ...}];

for (let i = 0, l = items.length; i < l; ++i) {
  if (items[i].id === findThis) {
    items[i].iAmChanged = true;
    break;
  }
}

แม้ว่าฉันจะเป็นแฟนตัวยงของฟังก์ชันอาร์เรย์ แต่อย่าปล่อยให้มันเป็นเครื่องมือเดียวในกล่องเครื่องมือของคุณ หากจุดประสงค์คือการกลายพันธุ์ของอาร์เรย์แสดงว่าไม่เหมาะสมที่สุด


0

ซับเดียวโดยใช้ตัวดำเนินการกระจาย

 const updatedData = originalData.map(x => (x.id === id ? { ...x, updatedField: 1 } : x));
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.