J'ai donc un tableau d'objets comme ça:
var arr = [
{uid: 1, name: "bla", description: "cucu"},
{uid: 2, name: "smth else", description: "cucarecu"},
]
uid
est l'identifiant unique de l'objet dans ce tableau. Je cherche la manière élégante de modifier l'objet si nous avons l'objet avec le uid,
Donné ou d'ajouter un nouvel élément, si le uid
présenté n'existe pas dans le tableau. J'imagine que la fonction doit se comporter comme ça dans la console js:
> addOrReplace(arr, {uid: 1, name: 'changed name', description: "changed description"})
> arr
[
{uid: 1, name: "bla", description: "cucu"},
{uid: 2, name: "smth else", description: "cucarecu"},
]
> addOrReplace(arr, {uid: 3, name: 'new element name name', description: "cocoroco"})
> arr
[
{uid: 1, name: "bla", description: "cucu"},
{uid: 2, name: "smth else", description: "cucarecu"},
{uid: 3, name: 'new element name name', description: "cocoroco"}
]
Ma façon actuelle ne semble pas très élégante et fonctionnelle:
function addOrReplace (arr, object) {
var index = _.findIndex(arr, {'uid' : object.uid});
if (-1 === index) {
arr.Push(object);
} else {
arr[index] = object;
}
}
J'utilise lodash, donc je pensais à quelque chose comme _.union
Modifié avec un contrôle d'égalité personnalisé.
Vous pouvez utiliser un objet au lieu d'un tableau :
var hash = {
'1': {uid: 1, name: "bla", description: "cucu"},
'2': {uid: 2, name: "smth else", description: "cucarecu"}
};
Les clés sont les uids . Maintenant, votre fonction addOrReplace
est simple comme ceci:
function addOrReplace(hash, object) {
hash[object.uid] = object;
}
[~ # ~] mise à jour [~ # ~]
Il est également possible d'utiliser un objet comme index en plus du tableau.
De cette façon, vous avez des recherches rapides ainsi qu'un tableau fonctionnel:
var arr = [],
arrIndex = {};
addOrReplace({uid: 1, name: "bla", description: "cucu"});
addOrReplace({uid: 2, name: "smth else", description: "cucarecu"});
addOrReplace({uid: 1, name: "bli", description: "cici"});
function addOrReplace(object) {
var index = arrIndex[object.uid];
if(index === undefined) {
index = arr.length;
arrIndex[object.uid] = index;
}
arr[index] = object;
}
Jetez un oeil à la jsfiddle-demo (une solution orientée objet que vous trouverez ici =)
Dans votre première approche, pas besoin de Lodash grâce à findIndex()
:
function addOrReplace(array, item) { // (1)
const i = array.findIndex(_item => _item.id === item.id);
if (i > -1) array[i] = item; // (2)
else array.Push(item);
}
Exemple:
const array = [
{id: 0, name: 'Apple', description: 'fruit'},
{id: 1, name: 'Banana', description: 'fruit'},
{id: 2, name: 'Tomato', description: 'vegetable'}
];
addOrReplace(array, {id: 2, name: 'Tomato', description: 'fruit'})
console.log(array);
/* =>
[
{id: 0, name: 'Apple', description: 'fruit'},
{id: 1, name: 'Banana', description: 'fruit'},
{id: 2, name: 'Tomato', description: 'fruit'}
]
*/
addOrReplace(array, {id: 3, name: 'Cucumber', description: 'vegetable'})
console.log(array);
/* =>
[
{id: 0, name: 'Apple', description: 'fruit'},
{id: 1, name: 'Banana', description: 'fruit'},
{id: 2, name: 'Tomato', description: 'fruit'},
{id: 3, name: 'Cucumber', description: 'vegetable'}
]
*/
(1) autres noms possibles: addOrUpdate()
, upsert()
, appendOrUpdate()
, insertOrUpdate()
...
(2) peut également être fait avec array.splice(i, 1, item)
Notez que cette approche est "mutable" (vs "immuable"): cela signifie qu'au lieu de retourner un nouveau tableau (sans toucher le tableau d'origine), il modifie directement le tableau d'origine. La plupart du temps, c'est ce que vous voulez.
Ancien poste, mais pourquoi ne pas utiliser la fonction de filtrage?
// If you find the index of an existing uid, save its index then delete it
// --- after the filter add the new object.
function addOrReplace( argh, obj ) {
var index = -1;
argh.filter((el, pos) => {
if( el.uid == obj.uid )
delete argh[index = pos];
return true;
});
// put in place, or append to list
if( index == -1 )
argh.Push(obj);
else
argh[index] = obj;
}
Voici un jsfiddle montrant comment cela fonctionne.
Peut être
_.mixin({
mergeById: function mergeById(arr, obj, idProp) {
var index = _.findIndex(arr, function (elem) {
// double check, since undefined === undefined
return typeof elem[idProp] !== "undefined" && elem[idProp] === obj[idProp];
});
if (index > -1) {
arr[index] = obj;
} else {
arr.Push(obj);
}
return arr;
}
});
et
var elem = {uid: 3, name: 'new element name name', description: "cocoroco"};
_.mergeById(arr, elem, "uid");
Personnellement, je n'aime pas les solutions qui modifient le tableau/objet d'origine, c'est donc ce que j'ai fait:
function addOrReplaceBy(arr = [], predicate, getItem) {
const index = _.findIndex(arr, predicate);
return index === -1
? [...arr, getItem()]
: [
...arr.slice(0, index),
getItem(arr[index]),
...arr.slice(index + 1)
];
}
Et vous l'utiliseriez comme:
var stuff = [
{ id: 1 },
{ id: 2 },
{ id: 3 },
{ id: 4 },
];
var foo = { id: 2, foo: "bar" };
stuff = addOrReplaceBy(
stuff,
{ id: foo.id },
(elem) => ({
...elem,
...foo
})
);
J'ai décidé de le rendre plus flexible:
lodash -> _.findIndex()
, le prédicat peut être multiplegetItem()
, vous pouvez décider de remplacer complètement l'élément ou de faire quelques modifications, comme je l'ai fait dans mon exemple.Remarque: cette solution contient certaines fonctionnalités ES6 telles que la déstructuration, les fonctions flèches, entre autres.
Et si les index du tableau étaient identiques à ceux de uid
?, Comme:
arr = [];
arr[1] = {uid: 1, name: "bla", description: "cucu"};
arr[2] = {uid: 2, name: "smth else", description: "cucarecu"};
de cette façon, vous pouvez simplement utiliser
arr[affectedId] = changedObject;