在lodash中有一个函数来replace匹配的项目

我想知道是否有更简单的方法在lodash中replaceJavaScript集合中的项目? (可能重复,但我不明白的答案:)

我看着他们的文档,但找不到任何东西

我的代码是:

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

更新:我想要replace的对象有很多属性

{id:1,Prop1:…,Prop2:…等等}

解:

感谢dfsq,但是我在lodash中find了一个合适的解决scheme,似乎工作正常,而且非常整齐,我把它放在一个mixin中,因为我在许多地方都有这个要求。 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)); 

更快的解决scheme正如@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); } }; 

在你的情况下,你只需要在数组中find对象并使用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="ajax/libs/lodash.js/2.4.1/lodash.min.js"></script> 
 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); } 

现在我们来testing所有方法的性能:

 // TC's first approach function first(arr, a, b) { _.each(arr, function (x, idx) { if (x.id === a.id) { arr[idx] = b; return false; } }); } // solution with merge function second(arr, a, b) { const match = _.find(arr, a); if (match) { _.merge(match, b); } else { arr.push(b); } } // most voted solution function third(arr, a, b) { const match = _.find(arr, a); if (match) { var index = _.indexOf(arr, _.find(arr, a)); arr.splice(index, 1, b); } else { arr.push(b); } } // my approach function fourth(arr, a, b){ let l; for(l=0; l < arr.length && arr[l].id != a.id; l++) {} l < arr.length ? arr[l] = b : arr.push(b); } function test(fn, times, el) { const arr = [], size = 250; for (let i = 0; i < size; i++) { arr[i] = {id: i, name: `name_${i}`, test: "test"}; } let start = Date.now(); _.times(times, () => { const id = Math.round(Math.random() * size); const a = {id}; const b = {id, name: `${id}_name`}; fn(arr, a, b); }); el.innerHTML = Date.now() - start; } test(first, 1e5, document.getElementById("first")); test(second, 1e5, document.getElementById("second")); test(third, 1e5, document.getElementById("third")); test(fourth, 1e5, document.getElementById("fourth")); 
 <script src="ajax/libs/lodash.js/4.14.1/lodash.min.js"></script> <div> <ol> <li><b id="first"></b> ms [TC's first approach]</li> <li><b id="second"></b> ms [solution with merge]</li> <li><b id="third"></b> ms [most voted solution]</li> <li><b id="fourth"></b> ms [my approach]</li> </ol> <div> 

您也可以使用findIndex并select以获得相同的结果:

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

看起来像最简单的解决scheme将使用ES6的.map或lodash的_.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; }); 

这有避免突变原始数组的好效果。

如果新对象的插入点不需要与前一个对象的索引相匹配,那么使用_.reject最简单的方法是使用_.reject ,然后将新值_.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" }] 

随着时间的推移,你应该采取一种更为实用的方法,避免数据突变,编写小型的单一责任函数。 使用ECMAScript 6标准,您可以使用提供的mapfilterreduce方法,在JavaScript中享受函数式编程范例。 你不需要另一个lodash,下划线或其他什么做最基本的事情。

在下面,我已经提出了一些解决这个问题的build议,以显示如何使用不同的语言function来解决这个问题:

使用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) 

如果你正在寻找一种不变的方式来改变集合(就像当我发现你的问题的时候一样),你可以看看不变性的帮手 ,一个从原来的React util分支的库。 在你的情况下,你可以通过以下方式完成你提到的内容:

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