есть ли функция в lodash для замены соответствующего элемента
интересно, есть ли более простой метод в lodash для замены элемента в коллекции JavaScript? (Возможно дублировать но я не понял ответа:)
Я посмотрел на их документацию, но ничего не смог найти
мой код:
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);
});
обновление: Объект, который я пытаюсь заменить, имеет много свойств, таких как
{id: 1, Prop1:..., Prop2:..., и ВКЛ}
устранение:
спасибо dfsq но я нашел правильное решение в lodash, которое, кажется, работает нормально и довольно аккуратно, и я положил его в миксин, так как у меня есть это требование во многих местах. 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);
}
};
10 ответов:
в вашем случае все, что вам нужно сделать, это найти объект в массив и использовать
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>
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); }
Теперь давайте проверим производительность для всех методов:
// 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="https://cdnjs.cloudflare.com/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>
кажется, что самое простое решение-использовать ES6
.map
или лодашь это_.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; });
Это имеет хороший эффект, избегая мутации исходного массива.
вы также можете использовать findIndex и pick для достижения того же результата:
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); }
[ES6] этот код работает для меня.
let result = array.map(item => item.id === updatedItem.id ? updatedItem : item)
С течением времени вы должны принять более функциональный подход, в котором вы должны избегать мутаций данных и писать небольшие, одиночные функции ответственности. С помощью стандарта ECMAScript 6 Вы можете наслаждаться парадигмой функционального программирования в JavaScript с предоставленным
map
,filter
иreduce
методы. Вам не нужен еще один lodash, подчеркивание или что еще делать самые основные вещи.ниже я включил некоторые предлагаемые решения этой проблемы, чтобы показать как эта проблема может быть решена с помощью различных функций языка:
использование карты 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)
рекурсивная версия - эквивалент сопоставление:
требует деструктурируется и массив распространения.
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
как HashMap структуры данных. Очень удобно, если у вас уже есть коллекция ключей какobject
- в противном случае вы должны изменить свое представление в первую очередь.требует объект rest spread,вычисляемые имена свойств и
Если точка вставки нового объекта не должна совпадать с индексом предыдущего объекта, то самый простой способ сделать это с помощью lodash-использовать
_.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" }]
Если вы ищете способ неизменно изменить коллекцию (как я был, когда я нашел ваш вопрос), вы можете взглянуть на неизменность-помощника, библиотека, разветвленная от исходного 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"}]
Если вы просто пытаетесь заменить одно свойство, lodash
_.find
и_.set
должно быть достаточно:var arr = [{id: 1, name: "Person 1"}, {id: 2, name: "Person 2"}]; _.set(_.find(arr, {id: 1}), 'name', 'New Person');
вы можете сделать это без использования lodash.
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")