est-il une fonction dans lodash à remplacer l'article correspondant

je me demande s'il existe une méthode plus simple dans lodash pour remplacer un article dans une collection JavaScript? (Possible dupliquer mais je n'ai pas compris la réponse:)

j'ai regardé leur documentation mais je n'ai rien trouvé

mon code est:

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

mise à Jour: L'objet que j'essaie de remplacer A de nombreuses propriétés comme

: 1, Prop1: ..., Prop2:... et ainsi de suite}

Solution:

merci à dfsq mais j'ai trouvé une bonne solution dans lodash qui semble fonctionner très bien et est assez soigné et je l'ai mis dans un mixin aussi bien puisque j'ai cette exigence à de nombreux endroits. 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));

Solution Plus Rapide Comme le souligne @dfsq, suivre est une façon plus rapide

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);
    }
};
80
demandé sur Community 2014-12-24 23:06:31

10 réponses

dans votre cas tout ce que vous devez faire est de trouver l'objet dans le tableau et d'utiliser Array.prototype.splice méthode:

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>
117
répondu dfsq 2017-05-15 09:15:35
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);
}

maintenant, testons les performances pour toutes les méthodes:

// 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>
16
répondu evilive 2017-05-19 08:19:26

semble comme la solution la plus simple utiliserait ES6 .map ou 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;
});

cela a l'effet agréable d'éviter de muter le tableau d'origine.

13
répondu Spencer 2017-01-23 05:30:30

vous pouvez également utiliser findIndex et pick pour obtenir le même résultat:

  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);
  }
8
répondu JVitela 2015-08-28 13:49:06

[ES6] ce code fonctionne pour moi.

let result = array.map(item => item.id === updatedItem.id ? updatedItem : item)
5
répondu shebik 2018-08-23 09:52:42

comme le temps passe, vous devriez adopter une approche plus fonctionnelle dans laquelle vous devriez éviter les mutations de données et écrire de petites, uniques fonctions de responsabilité. Avec la norme ECMAScript 6, Vous pouvez profiter du paradigme de programmation fonctionnelle en JavaScript avec les méthodes fournies map , filter et reduce . Vous n'avez pas besoin d'un autre lodash, underscore ou quoi d'autre pour faire les choses les plus basiques.

ci-dessous, j'ai inclus quelques solutions proposées pour ce problème afin de montrer comment ce problème peut être résolu en utilisant différentes caractéristiques linguistiques:

utilisant la carte 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)

une version Récursive - l'équivalent de la cartographie:

nécessite déstructuration et spread array .

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)

lorsque l'ordre final du tableau n'est pas important, vous pouvez utiliser un object comme une structure de données HashMap . Très pratique si vous avez déjà la collection de touches comme un object - sinon vous devez changer votre représentation d'abord.

Exige objet reste propagation , calculé les noms de propriété et Objet.rubriques .

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)
4
répondu Przemysław Zalewski 2017-05-21 15:36:31

si le point d'insertion du nouvel objet n'a pas besoin de correspondre à l'index de l'objet précédent, alors la façon la plus simple de le faire avec lodash est d'utiliser _.reject et de pousser de nouvelles valeurs dans le tableau:

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 vous avez plusieurs valeurs que vous voulez remplacer en une seule passe, vous pouvez faire ce qui suit (écrit dans un format non-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" }]
1
répondu richt 2017-03-31 13:14:26

si vous cherchez un moyen de changer immuablement la collection (comme je l'étais quand j'ai trouvé votre question), vous pourriez jeter un oeil à immutabilité-helper , une bibliothèque bifurquée de la réaction originale util. Dans votre cas, vous accompliriez ce que vous avez mentionné par l'intermédiaire de ce qui suit:

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
répondu Aaron_H 2017-04-26 23:02:23

si vous essayez juste de remplacer une propriété, lodash _.find et _.set devraient suffire:

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

_.set(_.find(arr, {id: 1}), 'name', 'New Person');
0
répondu Andrei Gavrilov 2018-05-16 15:15:25

vous pouvez le faire sans utiliser 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") 
0
répondu Sunny 2018-09-08 00:12:46