Javascript中的连接操作

16

我有2个对象列表:

people = 
[{id: 1, name: "Tom", carid: 1},
 {id: 2, name: "Bob", carid: 1},
 {id: 3, name: "Sir Benjamin Rogan-Josh IV", carid: 2}];

cars=
[{id: 1, name: "Ford Fiesta", color: "blue"},
 {id: 2, name: "Ferrari", color: "red"},
 {id: 3, name: "Rover 25", color: "Sunset Melting Yellow with hints of yellow"}];

是否有一个函数(可能在Angular,JQuery,Underscore,LoDash或其他外部库中)可以在一行上完成这些数据的左连接?例如:

peoplewithcars = leftjoin( people, cars, "carid", "id");

我可以自己写,但如果 LoDash 有优化过的版本,我想使用它。

9个回答

9

这个实现使用了ES6扩展运算符。再次说明,这不是一个库函数。

const leftJoin = (objArr1, objArr2, key1, key2) => objArr1.map(
    anObj1 => ({
        ...objArr2.find(
            anObj2 => anObj1[key1] === anObj2[key2]
        ),
        ...anObj1
    })
);

聪明的解决方案。但是,如果我们尝试在两个表中将“carid”用作卡ID的名称,则会失败。我没有看到在代码中轻松解决此问题的方法。@ЕрланЯр-Мухамедов提出的解决方案解决了这个问题。 - John Pankowicz
@JohnPankowicz 不确定您所说的“卡片ID名称”是什么意思,请提供示例数据。 - Ashley Wilson
在设计数据结构时,为了同一属性的可读性更高,最好在每个地方使用相同的属性名称。因此,“cars”数组的第一个成员将是:[{carid: 1, name: "Ford Fiesta" ...但是当我将“id”更改为“carid”时,您的左连接失败了。我相信有一种方法可以解决这个问题,但我无法看到如何解决。最终,我在我的代码中使用了ЕрланЯр的解决方案。 - John Pankowicz
@JohnPankowicz 和任何左连接一样,第一个表格优先,因此如果两个对象中都出现相同的键,则右边对象上的键将被覆盖。如果您有匹配的集合,可以颠倒表格的顺序来获取合并集。请参见CodePen:https://codepen.io/lifenstein/pen/VwxWjxL?editors=0012(但另一个解决方案并不通用) - Ashley Wilson
你可以将对象(表)名称作为键的前缀,以强制它们保持唯一。 - Ashley Wilson

6
您可以使用Alasql JavaScript SQL库来连接两个或多个对象数组:
var res = alasql('SELECT people.name AS person_name, cars.name, cars.color \
    FROM ? people LEFT JOIN ? cars ON people.carid = cars.id',[people, cars]);

请在jsFiddle上尝试这个例子


5

4

使用underscore.js实现并不难。

function leftJoin(left, right, left_id, right_id) {
    var result = [];
    _.each(left, function (litem) {
        var f = _.filter(right, function (ritem) {
            return ritem[right_id] == litem[left_id];
        });
        if (f.length == 0) {
            f = [{}];
        }
        _.each(f, function (i) {
            var newObj = {};
            _.each(litem, function (v, k) {
                newObj[k + "1"] = v;
            });
            _.each(i, function (v, k) {
                newObj[k + "2"] = v;
            });
            result.push(newObj);
        });
    });
    return result;
}

leftJoin(people, cars, "carid", "id");

4
你可以使用纯 JavaScript 来完成这些操作。
people.map(man => 
        cars.some(car => car.id === man.carid) ? 
            cars.filter(car => car.id === man.carid).map(car => ({car, man})) : 
            {man}
        ).reduce((a,b)=> a.concat(b),[]);

也是一个非常聪明的解决方案。而且它解决了我在@AshleyWilson那个方案中遇到的问题。 - John Pankowicz

2

不,LoDash没有join方法,但是自己实现很容易。下面这个例子并不完全是join,它只是选择所有拥有相同车型的人:

    var peopleWithCars = _.filter(people, function (person) {
        return _.exists(cars, function(car) {
            return car.id === person.id;
        });
    });

0

这个例子使用Lodash来左连接第一个匹配的对象。虽然不完全符合问题要求,但我发现类似的答案很有帮助。

var leftTable = [{
  leftId: 4,
  name: 'Will'
}, {
  leftId: 3,
  name: 'Michael'
}, {
  leftId: 8,
  name: 'Susan'
}, {
  leftId: 2,
  name: 'Bob'
}];

var rightTable = [{
  rightId: 1,
  color: 'Blue'
}, {
  rightId: 8,
  color: 'Red'
}, {
  rightId: 2,
  color: 'Orange'
}, {
  rightId: 7,
  color: 'Red'
}];

console.clear();

function leftJoinSingle(leftTable, rightTable, leftId, rightId) {
  var joinResults = [];

  _.forEach(leftTable, function(left) {
         var findBy = {};
      findBy[rightId] = left[leftId];

      var right = _.find(rightTable, findBy),
          result = _.merge(left, right);

      joinResults.push(result);
  })

  return joinResults;
}


var joinedArray = leftJoinSingle(leftTable, rightTable, 'leftId', 'rightId');
console.log(JSON.stringify(joinedArray, null, '\t'));

结果

[
 {
  "leftId": 4,
  "name": "Will"
 },
 {
  "leftId": 3,
  "name": "Michael"
 },
 {
  "leftId": 8,
  "name": "Susan",
  "rightId": 8,
  "color": "Red"
 },
 {
  "leftId": 2,
  "name": "Bob",
  "rightId": 2,
  "color": "Orange"
 }
]


0

数组

conap = ['1', '2', '7'];
avenida = ['1', '3', '5', '9'];

联合

union = [...conap, ...avenida]

加入

left_join = conap.filter((x) => !avenida.includes(x))

right_join = avenida.filter((x) => !conap.includes(x))
    
full_outer_join = [...(conap.filter((x) => !avenida.includes(x))), ...(avenida.filter((x) => !conap.includes(x)))]

-1
这是一个简单的循环,我为Javascript(在这种情况下是JQuery)编写的,用于根据someID“连接”obj1和obj2,并将obj2的一个属性添加到obj1中。
如果您想要进行更完整的连接,可以遍历obj2.hasOwnProperty()并将其复制过来。
    $.each(obj1,function(i){
        $.each(obj2, function(k){
            if (obj2[k].someID == obj1[i].someID ){
                obj1[i].someValue = obj2[k].someValue;
            }
        });
     });

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接