मिलान किए गए आइटम को बदलने के लिए लॉश में एक फ़ंक्शन है


134

मुझे आश्चर्य है कि अगर एक जावास्क्रिप्ट संग्रह में एक आइटम को बदलने के लिए लॉश में एक सरल विधि है? (संभव डुप्लिकेट लेकिन मुझे वहां इसका जवाब समझ में नहीं आया :)

मैंने उनके प्रलेखन को देखा, लेकिन कुछ भी नहीं मिला

मेरा कोड है:

var arr = [{id: 1, name: "Person 1"}, {id:2, name:"Person 2"}];
// Can following code be reduced to something like _.XX(arr, {id:1}, {id:1, name: "New Name"});
_.each(arr, function(a, idx){
  if(a.id === 1){
    arr[idx] = {id:1, name: "Person New Name"};
    return false;
  }
});

_.each(arr, function(a){
  document.write(a.name);
});

अद्यतन: मैं जिस वस्तु को बदलने की कोशिश कर रहा हूं, उसमें कई गुण हैं

{आईडी: १, प्रोप १: ..., प्रोप २: ..., इत्यादि

उपाय:

Dfsq के लिए धन्यवाद, लेकिन मुझे लॉश के भीतर एक उचित समाधान मिला जो कि ठीक काम करता है और बहुत साफ-सुथरा है और मैंने इसे एक मिक्सिन में डाल दिया है और साथ ही साथ मुझे कई जगहों पर इसकी आवश्यकता है। JSBin

var update = function(arr, key, newval) {
  var match = _.find(arr, key);
  if(match)
    _.merge(match, newval);
  else
    arr.push(newval);    
};

_.mixin({ '$update': update });

var arr = [{id: 1, name: "Person 1"}, {id:2, name:"Person 2"}];

_.$update(arr, {id:1}, {id:1, name: "New Val"});


document.write(JSON.stringify(arr));

तेज़ समाधान @dfsq द्वारा बताया गया है, निम्नलिखित तेजी से रास्ता है

var upsert = function (arr, key, newval) {
    var match = _.find(arr, key);
    if(match){
        var index = _.indexOf(arr, _.find(arr, key));
        arr.splice(index, 1, newval);
    } else {
        arr.push(newval);
    }
};

7
मुझे लगता है कि आप अपने "फास्टर सॉल्यूशन" के लियोन 4 पर दूसरे परम के रूप में _.indexOf के रूप में मैच का उपयोग कर सकते हैं, साथ ही, वहाँ उस मूल्य को पुनर्गणना करने की आवश्यकता नहीं है, जो चीजों को थोड़ा तेज करना चाहिए।
डेवट्रॉन

2
और भी तेज: _.findIndexमैच के लिए उपयोग करें ।
जूलियन के

1
@JulianK और @davertron ने जो कहा है, उस पर विस्तार करने के लिए, _.findIndexइसके बजाय _.findआप दूसरे _.findऔर a दोनों को छोड़ देंगे _.indexOf। आप 3 बार सरणी के माध्यम से पुनरावृत्ति कर रहे हैं जब आपको सभी की आवश्यकता होती है 1.
जस्टिन मॉर्गन 14

जवाबों:


191

आपके मामले में आपको केवल सरणी और उपयोग Array.prototype.splice()विधि में ऑब्जेक्ट ढूंढना है , अधिक विवरण यहां पढ़ें :

var arr = [{id: 1, name: "Person 1"}, {id:2, name:"Person 2"}];

// Find item index using _.findIndex (thanks @AJ Richardson for comment)
var index = _.findIndex(arr, {id: 1});

// Replace item at index using native splice
arr.splice(index, 1, {id: 100, name: 'New object.'});

// "console.log" result
document.write(JSON.stringify( arr ));
<script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.min.js"></script>


1
वैसे आपका समाधान प्रदर्शन के मामले में अधिक खर्च करने वाला है, क्योंकि indexOfयह बहुत तेज़ होने वाला है (यह मूल ब्राउज़र Array.prototype.indexOf का उपयोग करेगा)। लेकिन वैसे भी, खुशी से आपको एक समाधान मिलता है जो आपके लिए काम करता है।
dfsq

14
उपयोग क्यों नहीं _.findIndex? फिर आपको उपयोग करने की आवश्यकता नहीं है _.indexOf
एजे रिचर्डसन

35

.mapईएस 6 या लॉश का उपयोग करने के लिए सबसे सरल समाधान की तरह लगता है _.map:

var arr = [{id: 1, name: "Person 1"}, {id: 2, name: "Person 2"}];

// lodash
var newArr = _.map(arr, function(a) {
  return a.id === 1 ? {id: 1, name: "Person New Name"} : a;
});

// ES6
var newArr = arr.map(function(a) {
  return a.id === 1 ? {id: 1, name: "Person New Name"} : a;
});

यह मूल सरणी को बदलने से बचने का अच्छा प्रभाव है।


8
लेकिन आप हर बार एक नई व्यूह रचना कर रहे हैं ... ध्यान दें।
kboom

3
एक नया सरणी नहीं बनाने का एकमात्र विकल्प हालांकि मौजूदा एक को बदलना है। इसके अलावा, एक नई सरणी बनाने से प्रदर्शन के मामले में कोई प्रभाव नहीं पड़ेगा। मुझसे उपर उठो।
नोबिता

24

[ES6] यह कोड मेरे लिए काम करता है।

let result = array.map(item => item.id === updatedItem.id ? updatedItem : item)

1. आप सरणी का एक नया उदाहरण बना रहे हैं, इसलिए यह सही नहीं है कि एक आइटम को "प्रतिस्थापित" किया जाए। 2. updatedItemयदि आपकी सरणी खो जाती है तो उसी के साथ एक आइटम शामिल नहीं होगा id
दुष्ट

यह 'अपडेट' न करने वाले 'अपडेट' के लिए समाधान है (सवाल "MATCHED आइटम को बदलने के लिए लॉश में एक फ़ंक्शन है") और हाँ, यह सरणी की एक प्रति बनाता है, इसलिए यदि आप के साथ काम करने की आवश्यकता है तो इसका उपयोग न करें उसी सरणी (मैंने नहीं किया)
15

21
function findAndReplace(arr, find, replace) {
  let i;
  for(i=0; i < arr.length && arr[i].id != find.id; i++) {}
  i < arr.length ? arr[i] = replace : arr.push(replace);
}

अब सभी तरीकों के लिए प्रदर्शन का परीक्षण करें:


6
लोगों के साथ नकारात्मक होने के कारण नकारात्मक ("यह किसी तरह का मजाक है") उन्हें सीखने से दूर कर देता है। सोचिए अगर मैंने इसे "एक स्मार्ट व्यक्ति होने के नाते समाप्त किया है तो मैं उम्मीद करूंगा कि आप अपनी भावनाओं के बारे में आलसी न हों और उस बारे में सोचें"।
आदित्य सांसद

5
मैं किसी को चोट नहीं पहुंचाना चाहता था, लेकिन मुझे आश्चर्य है कि मूल विषय निर्माता के दृष्टिकोण से सबसे खराब समाधान को इतने वोट कैसे मिले। उसके लिए अपना वोट देने वाले लोगों के क्या नियम हैं? और मैंने इस बात को खारिज कर दिया कि लोग आँख बंद करके सबसे ज्यादा वोट देने वाले जवाब पर भरोसा करते हैं और महत्वपूर्ण सोच नहीं रखते।
दुष्ट

1
@ ईविल वैलिड पॉइंट्स, लेकिन मैं यह नहीं देखता कि उन लोगों को आपके सामने कैसे आना चाहिए, हालाँकि हर कोई जो पहले दिए गए जवाब / वोट बेवकूफ हैं। इस उत्तर के तथ्यात्मक हिस्से महान हैं, बाकी में बमुश्किल निहित श्रेष्ठता की हवा है। यह किसी की मदद नहीं करता है। आप अत्यधिक भावनात्मक प्रतिक्रिया के बिना आसानी से अपनी बात बना सकते हैं।
Thor84no

1
यह ध्यान देने योग्य है कि आपका समाधान और टीसी का समाधान केवल आईडी द्वारा फ़िल्टर किया जा रहा है। यही पहला कारण है कि वे दोनों तेजी से भाग रहे हैं। अन्य दो आपको फ़िल्टरिंग के लिए जिस भी वस्तु की आवश्यकता होती है, उसे उत्तीर्ण करने की अनुमति दे सकते हैं, जो कि एक मुखर फ़ंक्शन के रूप में अधिक बेहतर हो सकता है।
अराम

10

आप findIndex का उपयोग कर सकते हैं और समान परिणाम प्राप्त करने के लिए चुन सकते हैं:

  var arr  = [{id: 1, name: "Person 1"}, {id:2, name:"Person 2"}];
  var data = {id: 2, name: 'Person 2 (updated)'};
  var index = _.findIndex(arr, _.pick(data, 'id'));
  if( index !== -1) {
    arr.splice(index, 1, data);
  } else {
    arr.push(data);
  }

6

जैसे-जैसे समय बीतता है, आपको अधिक कार्यात्मक दृष्टिकोण अपनाना चाहिए जिसमें आपको डेटा म्यूटेशन से बचना चाहिए और छोटे, एकल जिम्मेदारी कार्यों को लिखना चाहिए। ECMAScript 6 मानक के साथ, आप प्रदान की गई जावास्क्रिप्ट के साथ कार्यात्मक प्रोग्रामिंग प्रतिमान का आनंद ले सकते हैं map, filterऔरreduce तरीकों। आपको किसी अन्य लॉश, अंडरस्कोर या सबसे बुनियादी चीजों को करने की आवश्यकता नहीं है।

नीचे मैंने इस समस्या के कुछ प्रस्तावित समाधानों को शामिल किया है ताकि यह दिखाया जा सके कि विभिन्न भाषा सुविधाओं का उपयोग करके इस समस्या को कैसे हल किया जा सकता है:

ES6 मानचित्र का उपयोग करना:

const replace = predicate => replacement => element =>
  predicate(element) ? replacement : element
 
const arr = [ { id: 1, name: "Person 1" }, { id:2, name:"Person 2" } ];
const predicate = element => element.id === 1
const replacement = { id: 100, name: 'New object.' }

const result = arr.map(replace (predicate) (replacement))
console.log(result)


पुनरावर्ती संस्करण - मानचित्रण के बराबर:

आवश्यक destructuring और सरणी प्रसार

const replace = predicate => replacement =>
{
  const traverse = ([head, ...tail]) =>
    head
    ? [predicate(head) ? replacement : head, ...tail]
    : []
  return traverse
}
 
const arr = [ { id: 1, name: "Person 1" }, { id:2, name:"Person 2" } ];
const predicate = element => element.id === 1
const replacement = { id: 100, name: 'New object.' }

const result = replace (predicate) (replacement) (arr)
console.log(result)


जब अंतिम सरणी का क्रम महत्वपूर्ण नहीं होता है तो आप हैशपॉप डेटा संरचना के objectरूप में उपयोग कर सकते हैं । बहुत आसान है अगर आपके पास पहले से ही एक के रूप में संग्रह है - अन्यथा आपको पहले अपना प्रतिनिधित्व बदलना होगा।object

आवश्यक वस्तु बाकी प्रसार , परिकलित प्रॉपर्टी नामों और Object.entries

const replace = key => ({id, ...values}) => hashMap =>
({
  ...hashMap,       //original HashMap
  [key]: undefined, //delete the replaced value
  [id]: values      //assign replacement
})

// HashMap <-> array conversion
const toHashMapById = array =>
  array.reduce(
    (acc, { id, ...values }) => 
    ({ ...acc, [id]: values })
  , {})
  
const toArrayById = hashMap =>
  Object.entries(hashMap)
  .filter( // filter out undefined values
    ([_, value]) => value 
  ) 
  .map(
    ([id, values]) => ({ id, ...values })
  )

const arr = [ { id: 1, name: "Person 1" }, { id:2, name:"Person 2" } ];
const replaceKey = 1
const replacement = { id: 100, name: 'New object.' }

// Create a HashMap from the array, treating id properties as keys
const hashMap = toHashMapById(arr)
console.log(hashMap)

// Result of replacement - notice an undefined value for replaced key
const resultHashMap = replace (replaceKey) (replacement) (hashMap)
console.log(resultHashMap)

// Final result of conversion from the HashMap to an array
const result = toArrayById (resultHashMap)
console.log(result)


5

यदि आप सिर्फ एक संपत्ति, लॉश को बदलने की कोशिश कर रहे हैं _.findऔर _.setपर्याप्त होना चाहिए:

var arr = [{id: 1, name: "Person 1"}, {id: 2, name: "Person 2"}];

_.set(_.find(arr, {id: 1}), 'name', 'New Person');

1

यदि नई ऑब्जेक्ट के सम्मिलन बिंदु को पिछले ऑब्जेक्ट के इंडेक्स से मेल खाने की आवश्यकता नहीं है, तो लॉश के साथ ऐसा करने का सबसे सरल तरीका उपयोग करके _.rejectऔर फिर नए मानों को सरणी में धकेलना है:

var arr = [
  { id: 1, name: "Person 1" }, 
  { id: 2, name: "Person 2" }
];

arr = _.reject(arr, { id: 1 });
arr.push({ id: 1, name: "New Val" });

// result will be: [{ id: 2, name: "Person 2" }, { id: 1, name: "New Val" }]

यदि आपके पास कई मान हैं जिन्हें आप एक पास में बदलना चाहते हैं, तो आप निम्न कार्य कर सकते हैं (गैर- ES6 प्रारूप में लिखित):

var arr = [
  { id: 1, name: "Person 1" }, 
  { id: 2, name: "Person 2" }, 
  { id: 3, name: "Person 3" }
];

idsToReplace = [2, 3];
arr = _.reject(arr, function(o) { return idsToReplace.indexOf(o.id) > -1; });
arr.push({ id: 3, name: "New Person 3" });
arr.push({ id: 2, name: "New Person 2" });


// result will be: [{ id: 1, name: "Person 1" }, { id: 3, name: "New Person 3" }, { id: 2, name: "New Person 2" }]

यह विधि सरणी सॉर्टिंग को बदल देती है
sospedra

1

लताड़ संघ का उपयोग करते हुए, आप किसी वस्तु के लिए एक सरल उभार को पूरा कर सकते हैं। प्रलेखन में कहा गया है कि अगर कोई मैच होता है, तो वह पहले सरणी का उपयोग करेगा। [] (सरणी) में अपनी अद्यतन की गई वस्तु लपेटें और इसे यूनियन फ़ंक्शन के पहले सरणी के रूप में डालें। बस अपने मिलान तर्क को निर्दिष्ट करें और यदि पाया गया तो वह इसे बदल देगा और यदि नहीं तो इसे जोड़ देगा

उदाहरण:

let contacts = [
     {type: 'email', desc: 'work', primary: true, value: 'email prim'}, 
     {type: 'phone', desc: 'cell', primary: true, value:'phone prim'},
     {type: 'phone', desc: 'cell', primary: false,value:'phone secondary'},
     {type: 'email', desc: 'cell', primary: false,value:'email secondary'}
]

// Update contacts because found a match
_.unionWith([{type: 'email', desc: 'work', primary: true, value: 'email updated'}], contacts, (l, r) => l.type == r.type && l.primary == r.primary)

// Add to contacts - no match found
_.unionWith([{type: 'fax', desc: 'work', primary: true, value: 'fax added'}], contacts, (l, r) => l.type == r.type && l.primary == r.primary)

1

बुरा संस्करण भी नहीं)

var arr = [{id: 1, name: "Person 1"}, {id: 2, name: "Person 2"}];

var id = 1; //id to find

arr[_.find(arr, {id: id})].name = 'New Person';


0

यदि आप संग्रह को पूरी तरह से बदलने के लिए रास्ता खोज रहे हैं (जैसा कि जब मैं आपका प्रश्न पाया गया था), तो आप अपरिवर्तनीयता-सहायक पर एक नज़र डाल सकते हैं , मूल प्रतिक्रिया के उपयोग से प्राप्त एक पुस्तकालय। आपके मामले में, आप निम्नलिखित के माध्यम से जो उल्लेख करेंगे उसे पूरा करेंगे:

var update = require('immutability-helper')
var arr = [{id: 1, name: "Person 1"}, {id:2, name:"Person 2"}]
var newArray = update(arr, { 0: { name: { $set: 'New Name' } } })
//=> [{id: 1, name: "New Name"}, {id:2, name:"Person 2"}]

0

आप इसे बिना लीश के उपयोग कर सकते हैं।

let arr = [{id: 1, name: "Person 1"}, {id: 2, name: "Person 2"}];
let newObj = {id: 1, name: "new Person"}

/*Add new prototype function on Array class*/
Array.prototype._replaceObj = function(newObj, key) {
  return this.map(obj => (obj[key] === newObj[key] ? newObj : obj));
};

/*return [{id: 1, name: "new Person"}, {id: 2, name: "Person 2"}]*/
arr._replaceObj(newObj, "id") 

0

अपरिवर्तनीय , के लिए उपयुक्तReactJS :

मान लीजिये:

cosnt arr = [{id: 1, name: "Person 1"}, {id:2, name:"Person 2"}];

अद्यतन की गई वस्तु दूसरी है और नाम को इसमें बदल दिया गया है Special Person:

const updatedItem = {id:2, name:"Special Person"};

सुझाव : lodash उपयोगी उपकरण है, लेकिन अब हम, पर Ecmascript6 + उनमें से कुछ है तो मैं बस का उपयोगmapसमारोह है कि दोनों की पर अस्तित्व में हैlodashऔरecmascript6+:

const newArr = arr.map(item => item.id === 2 ? updatedItem : item);

0

के रूप में अच्छी तरह से आया था और यह इस तरह से किया था।

const persons = [{id: 1, name: "Person 1"}, {id:2, name:"Person 2"}];
const updatedPerson = {id: 1, name: "new Person Name"}
const updatedPersons = persons.map(person => (
  person.id === updated.id
    ? updatedPerson
    : person
))

अगर हम चाहते तो इसे सामान्य कर सकते थे

const replaceWhere = (list, predicate, replacement) => {
  return list.map(item => predicate(item) ? replacement : item)
}

replaceWhere(persons, person => person.id === updatedPerson.id, updatedPerson)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.