如何使用Lodash基于密钥合并两个集合?

mur*_*lai 23 javascript collections merge lodash

我有两个集合,对象有一个公共密钥"userId".如下:

var _= require('lodash');

var a = [
  { userId:"p1", item:1},
  { userId:"p2", item:2},
  { userId:"p3", item:4}
];

var b = [
  { userId:"p1", profile:1},
  { userId:"p2", profile:2}
];
Run Code Online (Sandbox Code Playgroud)

我想基于"userId"合并它们以产生:

[ { userId: 'p1', item: 1, profile: 1 },
  { userId: 'p2', item: 2, profile:2 },
  { userId: 'p3', item: 4 } ]
Run Code Online (Sandbox Code Playgroud)

到目前为止我有这些:

var u = _.uniq(_.union(a, b), false, _.property('userId'));
Run Code Online (Sandbox Code Playgroud)

结果如下:

[ { userId: 'p1', item: 1 },
  { userId: 'p2', item: 2 },
  { userId: 'p3', item: 4 },
  { userId: 'p1', profile: 1 },
  { userId: 'p2', profile: 2 } ]
Run Code Online (Sandbox Code Playgroud)

我现在如何合并它们?

我试过_.keyBy,但结果是:

{ p1: { userId: 'p1', profile: 1 },
  p2: { userId: 'p2', profile: 2 },
  p3: { userId: 'p3', item: 4 } }
Run Code Online (Sandbox Code Playgroud)

这是错的.

我应该做的最后一步是什么?

Tus*_*har 34

你可以使用_.map(),_.assign()_.find().

// Iterate over first array of objects
_.map(a, function(obj) {

    // add the properties from second array matching the userID
    // to the object from first array and return the updated object
    return _.assign(obj, _.find(b, {userId: obj.userId}));
});
Run Code Online (Sandbox Code Playgroud)

小提琴演示

var a = [{
    userId: "p1",
    item: 1
}, {
    userId: "p2",
    item: 2
}, {
    userId: "p3",
    item: 4
}];

var b = [{
    userId: "p1",
    profile: 1
}, {
    userId: "p2",
    profile: 2
}];

var arrResult = _.map(a, function(obj) {
    return _.assign(obj, _.find(b, {
        userId: obj.userId
    }));
});

console.log(arrResult);
document.getElementById('result').innerHTML = JSON.stringify(arrResult, 0, 4);
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.1.0/lodash.min.js"></script>
<pre id="result"></pre>
Run Code Online (Sandbox Code Playgroud)

  • 只是想一想,如果第二个列表包含唯一的userId,则不会将其添加到最终列表中.我怀疑这是OP不想要的行为. (15认同)

Jor*_*jon 19

投票率最高的答案无法正确合并。如果第二个数组包含唯一属性,则不考虑它。

这种方法可以进行正确的合并。

洛达

var a = [
  { userId:"p1", item:1},
  { userId:"p2", item:2},
  { userId:"p3", item:4}
];

var b = [
  { userId:"p1", profile:1},
  { userId:"p2", profile:2},
  { userId:"p4", profile:4}
];
var merged = _.merge(_.keyBy(a, 'userId'), _.keyBy(b, 'userId'));
var values = _.values(merged);
console.log(values);
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
Run Code Online (Sandbox Code Playgroud)

ES6 +

// from https://stackoverflow.com/a/34749873/80766
const mergeDeep = (target, ...sources) => {
  if (!sources.length) return target;
  const source = sources.shift();

  if (target instanceof Object && source instanceof Object) {
    for (const key in source) {
      if (source[key] instanceof Object) {
        if (!target[key]) Object.assign(target, { [key]: {} });
        mergeDeep(target[key], source[key]);
      } else {
        Object.assign(target, { [key]: source[key] });
      }
    }
  }

  return mergeDeep(target, ...sources);
}

const a = [
  { userId:"p1", item:1},
  { userId:"p2", item:2},
  { userId:"p3", item:4}
];

const b = [
  { userId:"p1", profile:1},
  { userId:"p2", profile:2},
  { userId:"p4", profile:4}
];


const aKeyed = a.reduce((acc, cur) => ({ ...acc, [cur.userId]: cur }), {});
const bKeyed = b.reduce((acc, cur) => ({ ...acc, [cur.userId]: cur }), {});
const merged = mergeDeep(aKeyed, bKeyed);
const values = Object.values(merged);
console.log(values);
Run Code Online (Sandbox Code Playgroud)


Nic*_*uin 7

Lodash 有一个merge处理对象的方法(合并具有相同键的对象)。在这个演示中,数组ab首先被转换为对象(其中userId是键),然后合并,结果转换回数组(_.values)(去掉键)。_.flatten然后是必要的,因为_.values添加了额外的数组级别。

var u= _({}) // Start with an empty object
  .merge(
    _(a).groupBy("userId").value(),
    _(b).groupBy("userId").value()
  )
  .values()
  .flatten()
  .value();
Run Code Online (Sandbox Code Playgroud)


Nin*_*olz 6

只是为了完整性:一个没有任何图书馆的提案。

function merge(a, b, key) {

    function x(a) {
        a.forEach(function (b) {
            if (!(b[key] in obj)) {
                obj[b[key]] = obj[b[key]] || {};
                array.push(obj[b[key]]);
            }
            Object.keys(b).forEach(function (k) {
                obj[b[key]][k] = b[k];
            });
        });
    }

    var array = [],
        obj = {};

    x(a);
    x(b);
    return array;
}

var a = [
        { userId: "p1", item: 1 },
        { userId: "p2", item: 2 },
        { userId: "p3", item: 4 }
    ],
    b = [
        { userId: "p1", profile: 1 },
        { userId: "p2", profile: 2 }
    ],
    c = merge(a, b, 'userId');

document.write('<pre>' + JSON.stringify(c, 0, 4) + '</pre>');
Run Code Online (Sandbox Code Playgroud)