web-dev-qa-db-fra.com

Fusionner un tableau d'objets par propriété à l'aide de Lodash

J'ai deux tableaux d'objets qui représentent des adresses électroniques qui ont une étiquette et une valeur:

var original = [
  {
    label: 'private',
    value: '[email protected]'
  },
  {
    label: 'work',
    value: '[email protected]'
  }
];

var update = [
  {
    label: 'private',
    value: '[email protected]'
  },
  {
    label: 'school',
    value: '[email protected]'
  }
];

Maintenant, je veux comparer et fusionner les deux tableaux avec le champ label, pour que le résultat ressemble à ceci:

var result = [
  {
    label: 'private',
    value: '[email protected]'
  },
  {
    label: 'work',
    value: '[email protected]'
  },
  {
    label: 'school',
    value: '[email protected]'
  }
]

Comment puis-je faire cela, par exemple en utilisant lodash ?

32
benjiman

_.unionBy() :
Cette méthode est semblable à _.union, sauf qu'elle accepte iteratee, qui est invoqué pour chaque élément de chaque tableau afin de générer le critère permettant de calculer l'unicité. Les valeurs de résultat sont choisies dans le premier tableau dans lequel la valeur apparaît.

var original = [
  { label: 'private', value: '[email protected]' },
  { label: 'work', value: '[email protected]' }
];

var update = [
  { label: 'private', value: '[email protected]' },
  { label: 'school', value: '[email protected]' }
];

var result = _.unionBy(update, original, "label");

console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>

64
Andreas

Convertissez les listes en objets définis par label, fusionnez-les par _.assign et convertissez-les en tableau. Il conservera même l'ordre des éléments sur la plupart des navigateurs.

var original = [
  {
    label: 'private',
    value: '[email protected]'
  },
  {
    label: 'work',
    value: '[email protected]'
  }
];

var update = [
  {
    label: 'private',
    value: '[email protected]'
  },
  {
    label: 'school',
    value: '[email protected]'
  }
];

console.log(
  _.map(
    _.assign(
      _.mapKeys(original, v => v.label),
      _.mapKeys(update, v => v.label)
    )
  )
);


// or remove more duplicated code using spread

console.log(
  _.map(
    _.assign(
      ...[original, update].map(
        coll => _.mapKeys(coll, v => v.label)
      )
    )
  )
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.js"></script>

4
Tamas Hegedus

Peut-être un peu tard, mais toutes les solutions que j'ai vues ne joignent pas les deux tableaux correctement, ils utilisent l'un des tableaux à boucler et tous les éléments en surplus du second tableau ne sont pas ajoutés (en supposant que c'est ce qui est requis) .

La bonne façon de faire est de trier les deux tableaux et d’avancer dans les deux tableaux, en fusionnant les éléments de correspondance et en ajoutant les éléments manquants des deux tableaux . Veuillez trouver la solution complète ci-dessous. Cela prend aussi O (n + m) qui est le meilleur que vous puissiez obtenir (sans les coûts de calcul pour le tri lui-même). Dans mon code, j'ai déjà obtenu les données triées de la base de données.

function mergeObjectsBasedOnKey(array1, array2, compareFn, mergeFn, alreadySorted) {
  var array1Index = 0;
  var array2Index = 0;

  const merged = [];

  if (!alreadySorted) {
    array1.sort(compareFn);
    array2.sort(compareFn);
  }

  while (array1Index < array1.length && array2Index < array2.length) {
    var comparedValue = compareFn(array1[array1Index], array2[array2Index]);
    if (comparedValue === 0) {
      merged.Push(mergeFn(array1[array1Index], array2[array2Index]));
      array1Index++;
      array2Index++;
    } else if (comparedValue < 0) {
      merged.Push(mergeFn(array1[array1Index]));
      array1Index++;
    } else {
      merged.Push(mergeFn(array2[array2Index]));
      array2Index++;
    }
  }
  while (array1Index < array1.length) {
    merged.Push(mergeFn(array1[array1Index]));
    array1Index++;
  }
  while (array2Index < array2.length) {
    merged.Push(mergeFn(array2[array2Index]));
    array2Index++;
  }
  return merged;
}


const array1 = [{
    "id": 10,
    isArray1: true
  },
  {
    "id": 11,
    isArray1: true
  },
  {
    "id": 12,
    isArray1: true
  },
];
const array2 = [{
    "id": 8,
    isArray2: true
  },
  {
    "id": 11,
    isArray2: true
  },
  {
    "id": 15,
    isArray2: true
  },
];

const result = mergeObjectsBasedOnKey(array1, array2, function(a, b) {
  return a.id - b.id;
}, function(a, b) {
  if (b) {
    return _.merge(a, b);
  }
  return _.merge(a, {
    isArray1: true,
    isArray2: true
  });
});

console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>

Et les résultats seraient:

[ { id: 8, isArray2: true, isArray1: true },
  { id: 10, isArray1: true, isArray2: true },
  { id: 11, isArray1: true, isArray2: true },
  { id: 12, isArray1: true, isArray2: true },
  { id: 15, isArray2: true, isArray1: true } ]
2
Ralph

Si vous utilisez lodash 3.x où _.unionBy () n'était pas là, vous pouvez combiner _.union() et _.uniq() pour obtenir le même résultat.

var original = [
  { label: 'private', value: '[email protected]' },
  { label: 'work', value: '[email protected]' }
];

var update = [
  { label: 'private', value: '[email protected]' },
  { label: 'school', value: '[email protected]' }
];

var result = _.uniq(_.union(update, original), "label"); 

console.log(result);
1
Manish Kumar

Je sais que ce n'est pas ce qui est demandé, mais juste au cas où quelqu'un trébucherait sur cette page, voici comment vous le faites dans ramda:

var original = [
  { label: 'private', value: '[email protected]' },
  { label: 'work', value: '[email protected]' }
];

var updated = [
  { label: 'private', value: '[email protected]' },
  { label: 'school', value: '[email protected]' }
];

unionWith(eqBy(prop('label')), updated, original);
0
Revanth Kumar

Voici un autre moyen de fusionner deux objets à l'aide de Lodash:

let a = [{
    content: 'aaa',
    name: 'bbb2'
  },
  {
    content: 'aad',
    name: 'ccd'
  }
];

let b = [{
    content: 'aaa',
    name: 'bbb'
  },
  {
    content: 'aad1',
    name: 'ccd1'
  }
];

let c = [...a, ...b];

let d = _.uniq(c, function(data) {
  return data.content;
})

console.log(d);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.1/underscore-min.js"></script>

0
jain77