【问题标题】:Two arrays inner join in JavaScriptJavaScript中的两个数组内连接
【发布时间】:2021-04-07 20:27:46
【问题描述】:

以下是我拥有的 2 个数组,

 var g= [ 
        { id: 36, name: 'AAA', goal: 'yes' },
        { id: 40, name: 'BBB', goal: 'yes' },
        { id: 39, name: 'JJJ', goal: 'yes' },
        { id: 27, name: 'CCC', goal: 'yes' }];

    var c= [ 
        { id: 36, color:"purple" },
        { id: 40, color:"purple" },
        { id: 100, color:"pink"} ];

期望的输出(左连接'id'):

    res = [{ id: 36, name: 'AAA', goal: 'yes' , color:"purple"}, { id: 40, name: 'BBB', goal: 'yes', color:"purple" }]

这是一个合并的现有逻辑,但我正在寻找左连接的逻辑:

    function mergeBy(key, data) {
      return Array.from(data
          .reduce((m, o) => m.set(o[key], { ...m.get(o[key]), ...o }), new Map)
          .values()
      );
    }

【问题讨论】:

  • 数组是否按照id排序?
  • 这根本不是“左连接”。您的结果意味着只需添加对象出现在第一个数组中的第二个数组的属性 - 如果有更接近内部连接的任何内容。
  • @Jamiec:正如我在问题中所说,我有这个合并逻辑,但我不知道如何实现左连接。
  • @SomShekharMukherjee:目前没有,但可以排序
  • 但您不是要求左连接!您要求合并对象(类似于内部连接)。看看我的答案是不是你想要的

标签: javascript arrays join


【解决方案1】:

这里有一些加入,你可以选择!

function* innerJoin(a, b, key) {
    let idx = new Map(b.map(x => [key(x), x]));
    for (let x of a) {
        let k = key(x);
        if (idx.has(k))
            yield {...x, ...idx.get(k)};
    }
}

function* leftJoin(a, b, key) {
    let idx = new Map(b.map(x => [key(x), x]));
    for (let x of a) {
        let k = key(x);
        yield idx.has(k) ? {...x, ...idx.get(k)} : x;
    }
}

function* rightJoin(a, b, key) {
    let idx = new Map(a.map(x => [key(x), x]));
    for (let x of b) {
        let k = key(x);
        yield idx.has(k) ? {...idx.get(k), ...x} : x;
    }
}


//

var A = [
    {id: 1, a: 'a1'},
    {id: 2, a: 'a2'},
    {id: 7, a: 'a3'},
    {id: 8, a: 'a4'}
];

var B = [
    {id: 1, b: 'b1'},
    {id: 2, b: 'b2'},
    {id: 9, b: 'b3'}
];


console.log('INNER:')
console.log(...innerJoin(A, B, x => x.id))
console.log('LEFT')
console.log(...leftJoin(A, B, x => x.id))
console.log('RIGHT')
console.log(...rightJoin(A, B, x => x.id))

【讨论】:

    【解决方案2】:

    您的预期结果要求的不是左连接。您要求使用idgc 进行内部连接并合并属性。下面应该这样做

    var g= [ 
            { id: 36, name: 'AAA', goal: 'yes' },
            { id: 40, name: 'BBB', goal: 'yes' },
            { id: 39, name: 'JJJ', goal: 'yes' },
            { id: 27, name: 'CCC', goal: 'yes' }];
    
    var c= [ 
            { id: 36, color:"purple" },
            { id: 40, color:"purple" },
            { id: 100, color:"pink"} ];
        
    function mergeBy(key, dataL, dataR) {
      const rMap = dataR.reduce((m, o) => m.set(o[key], { ...m.get(o[key]), ...o }), new Map);
      
      return dataL.filter(x => rMap.get(x[key])).map(x => ({...x, ...rMap.get(x[key]) }));
    }
    
    console.log(mergeBy("id",g, c))

    【讨论】:

    • 这段代码很好用,如果键名不同,如何更新这段代码?例如:左键为 id1,右键为 id2 并加入这些数组
    【解决方案3】:

    您可以获得不常用的键并过滤合并的结果。

    const
        mergeCommon = (a, b, key) => {
            const aByKey = a.reduce((m, o) => m.set(o[key], o), new Map);
    
            return b.reduce((r, o) => {
                if (aByKey.has(o[key])) r.push({ ... aByKey.get(o[key]), ...o});
                return r;
            }, []);
        },
        g = [{ id: 36, name: 'AAA', goal: 'yes' , 'random': 27 }, { id: 40, name: 'BBB', goal: 'yes' }, { id: 39, name: 'JJJ', goal: 'yes' }, { id: 27, name: 'CCC', goal: 'yes' , lag: "23.3343" }],
        c = [{ id: 36, name: 'AAA', goal: 'yes', color:"purple" }, { id: 40, name: 'BBB', circle: 'yes', color:"purple" }, { id: 100, name: 'JJJ', circle: 'yes'}],
        result = mergeCommon(g, c, 'id');
    
    console.log(result);
    .as-console-wrapper { max-height: 100% !important; top: 0; }

    【讨论】:

    • 这甚至是左连接吗? Left Join 不应该包含第一个数组中的所有项目。
    • @SomShekharMukherjee,实际上它是一个内部连接。
    【解决方案4】:

    您可以使用Maps 连接两个数组。三种连接Left Join、Right Join、Inner Join见代码sn-p。

    所有三个连接都需要 O(N) 时间。

    const g = [
      { id: 36, name: 'AAA', goal: 'yes', random: 27 },
      { id: 40, name: 'BBB', goal: 'yes' },
      { id: 39, name: 'JJJ', goal: 'yes' },
      { id: 27, name: 'CCC', goal: 'yes', lag: '23.3343' },
    ];
    
    const c = [
      { id: 36, name: 'AAA', goal: 'yes', color: 'purple' },
      { id: 40, name: 'BBB', circle: 'yes', color: 'purple' },
      { id: 100, name: 'JJJ', circle: 'yes' },
    ];
    
    const gMap = new Map(g.map(o => [o.id, o]));
    const cMap = new Map(c.map(o => [o.id, o]));
    
    const leftJoin = g.reduce(
      (a, o) => (cMap.has(o.id) ? [...a, { ...o, ...cMap.get(o.id) }] : [...a, o]),
      []
    );
    
    const rightJoin = c.reduce(
      (a, o) => (gMap.has(o.id) ? [...a, { ...o, ...gMap.get(o.id) }] : [...a, o]),
      []
    );
    
    const innerJoin = g.reduce(
      (a, o) => (cMap.has(o.id) ? [...a, { ...o, ...cMap.get(o.id) }] : a),
      []
    );
    
    console.log("LEFT JOIN\n", leftJoin)
    console.log("RIGHT JOIN\n", rightJoin)
    console.log("INNER JOIN\n", innerJoin)

    【讨论】:

      【解决方案5】:

      var g = [ 
          { id: 36, name: 'AAA', goal: 'yes' , 'random':27},
          { id: 40, name: 'BBB', goal: 'yes' },
          { id: 39, name: 'JJJ', goal: 'yes' },
          { id: 27, name: 'CCC', goal: 'yes' , lag: "23.3343"}
      ];
      
      var c = [ 
          { id: 36, name: 'AAA', goal: 'yes', color:"purple" },
          { id: 40, name: 'BBB', circle: 'yes', color:"purple" },
          { id: 100, name: 'JJJ', circle: 'yes'} 
      ];
      
      
      const combinedArr = (arr1, arr2) => {
      //Filter the arr2 and find the only matching elements from the first array
          const filteredArr = arr2.filter(({id}) => arr1.some(({id: arr1Id}) => arr1Id === id));
          //Loop through the filtered array and fetch the matching item from first and add obj from filtered array
          return filteredArr.map(obj => {
              return {
                  ...arr1.find(({id}) => id === obj.id),
                  ...obj
              }
          })
      }    
      console.log(combinedArr(g, c));
      .as-console-wrapper { 
        max-height: 100% !important;
      }

      【讨论】:

        【解决方案6】:

        你去,一个班轮

         var g= [ 
                { id: 36, name: 'AAA', goal: 'yes' },
                { id: 40, name: 'BBB', goal: 'yes' },
                { id: 39, name: 'JJJ', goal: 'yes' },
                { id: 27, name: 'CCC', goal: 'yes' }];
        
            var c= [ 
                { id: 36, color:"purple" },
                { id: 40, color:"purple" },
                { id: 100, color:"pink"} ];
        
        
        
        const result = g.map(i => !!c.find(e => e.id === i.id) && ({...i, ...c.find(e => e.id === i.id)})).filter(Boolean);
        console.log(result);

        【讨论】:

          猜你喜欢
          • 2020-02-09
          • 1970-01-01
          • 1970-01-01
          • 2020-09-24
          • 1970-01-01
          • 1970-01-01
          • 2017-07-14
          • 1970-01-01
          相关资源
          最近更新 更多