underscore empty array javascript lodash

javascript - empty - ¿hay una función en lodash para reemplazar el elemento coincidente



lodash object empty (13)

Me pregunto si hay un método más simple en lodash para reemplazar un elemento en una colección de JavaScript. (Posible duplicate pero no entendí la respuesta allí :)

Miré su documentación pero no pude encontrar nada

Mi código es:

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

Actualización: el objeto con el que intento reemplazar tiene muchas propiedades como

{id: 1, Prop1: ..., Prop2: ..., y así sucesivamente}

Solución:

Gracias a dfsq pero encontré una solución adecuada dentro de lodash que parece funcionar bien y es bastante ordenada y también la puse en un mixin ya que tengo este requisito en muchos lugares. 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));

Solución más rápida Como lo señaló @dfsq, seguir es mucho más rápido

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


A medida que pasa el tiempo, debe adoptar un enfoque más funcional en el que debe evitar las mutaciones de datos y escribir pequeñas funciones de responsabilidad única. Con el estándar ECMAScript 6, puede disfrutar del paradigma de programación funcional en JavaScript con los métodos de map , filter y reduce . No necesita otro lodash, guión bajo o qué más hacer para hacer las cosas más básicas.

A continuación, he incluido algunas soluciones propuestas para este problema con el fin de mostrar cómo se puede resolver este problema utilizando diferentes características del lenguaje:

Usando el mapa 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)

Versión recursiva - equivalente de mapeo:

Requiere destructuring y dispersión de la matriz .

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)

Cuando el orden de la matriz final no es importante, puede usar un object como estructura de datos HashMap . Muy útil si ya tiene una colección con clave como object ; de lo contrario, primero debe cambiar su representación.

Requiere propagación de descanso de objetos , nombres de propiedades calculados y 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)


En su caso, todo lo que necesita hacer es encontrar el objeto en la matriz y usar el método 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>


No está mal la variante también)

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'';


Parece que la solución más simple sería usar .map de ES6 o _.map de _.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; });

Esto tiene el bonito efecto de evitar la mutación de la matriz original.


Puedes hacerlo sin usar 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")


Si el punto de inserción del nuevo objeto no necesita coincidir con el índice del objeto anterior, entonces la forma más simple de hacer esto con lodash es usar _.reject y luego introducir nuevos valores en la matriz:

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

Si tiene varios valores que desea reemplazar en una sola pasada, puede hacer lo siguiente (escrito en formato que no sea 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" }]


Si está buscando una manera de cambiar de manera inmutable la colección (como estaba cuando encontré su pregunta), puede echar un vistazo a immutability-helper , una biblioteca bifurcada de la utilidad React original. En su caso, lograría lo que mencionó a través de lo siguiente:

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


Si solo está tratando de reemplazar una propiedad, lodash _.find y _.set deberían ser suficientes:

var arr = [{id: 1, name: "Person 1"}, {id: 2, name: "Person 2"}]; _.set(_.find(arr, {id: 1}), ''name'', ''New Person'');


También puede usar findIndex y pick para lograr el mismo resultado:

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


Usando la función lodash unionWith, puede realizar una inserción simple a un objeto. La documentación indica que si hay una coincidencia, usará la primera matriz. Envuelva su objeto actualizado en [] (matriz) y colóquelo como la primera matriz de la función de unión. Simplemente especifique su lógica de coincidencia y, si la encuentra, la reemplazará y, de lo contrario, la agregará

Ejemplo:

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)


[ES6] Este código funciona para mí.

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


var arr= [{id: 1, name: "Person 1"}, {id:2, name:"Person 2"}]; var index = _.findIndex(arr, {id: 1}); arr[index] = {id: 100, name: ''xyz''}


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

Ahora probemos el rendimiento para todos los métodos:

// 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>