web-dev-qa-db-ja.com

Lodashを使用したプロパティによるオブジェクトの配列のマージ

ラベルと値を持つ電子メールアドレスを表すオブジェクトの2つの配列があります。

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

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

ここで、2つの配列をlabelフィールドで比較およびマージして、結果が次のようになるようにします。

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

どのようにこれを行うことができますか? lodash ?を使用

36
benjiman

_.unionBy()
このメソッドは_.unionに似ていますが、一意性を計算する基準を生成するために各配列の各要素に対して呼び出されるiterateeを受け入れる点が異なります。 結果値は、値が発生する最初の配列から選択されます

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>
76
Andreas

リストをlabelでキー設定されたオブジェクトに変換し、_.assignでそれらをマージし、配列に戻します。ほとんどのブラウザでアイテムの順序も保持されます。

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

私はそれが求めたものではないことを知っていますが、このページで誰かがつまずいた場合に備えて、ラムダでこれを行う方法があります:

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);
2
Revanth Kumar

おそらく少し遅れますが、私が見たすべてのソリューションは両方の配列を正しく結合せず、配列の1つを使用してループし、2番目の配列の余分な要素は追加されません(これが必要であると仮定) 。

正しい方法は、両方の配列をソートし、両方の配列内で前方に移動し、一致する要素をマージして、両方の配列から欠落している要素を追加することです。以下で完全なソリューションを見つけてください。また、これにはO(n + m)が必要です。これは(ソート自体の計算コストなしで)得ることができる最高のものです。私のコードでは、データベースからデータをソート済みです。

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>

結果は次のようになります。

[ { 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

_。unionBy()が存在しないlodash 3.xを使用している場合は、_.union()_.uniq()を組み合わせて同じ結果を得ることができます。

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

Lodashを使用して2つのオブジェクトをマージする別の方法を次に示します。

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