【问题标题】:Merge items from two arrays based on matching ID根据匹配的 ID 合并两个数组中的项目
【发布时间】:2019-09-06 13:55:51
【问题描述】:

我有一个这样的数据对象:

{
  "data1": [
    [
      "ID",
      "name",
      "Birthday"
    ],
    [
      "10",
      "thomas",
      "1992-03-17"
    ],
    [
      "11",
      "Emily",
      "2000-03-03"
    ]
  ],
  "data2": [
    [
      "Balance",
      "ID"
    ],
    [
      "$4500",
      "10"
    ],
    [
      "$1500",
      "13"
    ]
  ]
}

它包含两个数组data1data2。 每个数组的第一行是列的名称,其余行包含数据(将其视为表格)。

我想比较两个数组中的ID 字段,如果IDs 匹配,那么最终输出将包含Balance 列,余额对应于ID,如果IDs不匹配则Balance 将是$0

预期输出:

{
  "output": [
    [
      "ID",
      "name",
      "Birthday",
      "Balance"
    ],
    [
      "10",
      "thomas",
      "1992-03-17",
      "$4500" //ID 10 matched so the balance added here
    ],
    [
      "11",
      "Emily",
      "2000-03-03",
      "0" //0 bcoz the ID 11 is not there in data2 array
    ]
  ]

}

我觉得这很难完成。把它想象成 MySQL 中的 LEFT-JOIN。 我提到了这个solution,但它在我的情况下不起作用,因为我的回复中没有密钥。

编辑:我还需要加入其他领域。

【问题讨论】:

    标签: javascript arrays node.js sorting left-join


    【解决方案1】:

    您可以使用Array.prototype.map()findfilterslicereduceconcatincludesObject.assign()

    这个解决方案:

    • 处理项目的任意顺序。订单从标题中读取。
    • 仅当data2 中存在Balance 字段时才附加一个字段。
    • 加入所有其他字段(由 OP 要求,参见下面的 cmets)
    • 将默认值作为输入,如果data1data2 中不存在数据,则使用它们。

    function merge({ data1, data2 }, defaults) {
      // get the final headers, add/move 'Balance' to the end
      const headers = [...data1[0].filter(x => x !== 'Balance')]
        .concat(data2[0].includes('Balance') ? ['Balance'] : []);
      
      // map the data from data1 to an array of objects, each key is the header name, also merge the default values.
      const d1 = data1.slice(1)
        .map(x => x.reduce((acc, y, i) => ({ ...defaults, ...acc, [data1[0][i]]: y }), {}));
      // map the data from data2 to an array of objects, each key is the header name
      const d2 = data2.slice(1)
        .map(x => x.reduce((acc, y, i) => ({ ...acc, [data2[0][i]]: y }), {}));
      
      // combine d1 and d2
      const output = d1.map((x, i) => { // iterate over d1
        // merge values from d2 into this value
        const d = Object.assign(x, d2.find(y => y['ID'] === x['ID']));
        // return an array ordered according to the header
        return headers.map(h => d[h]);
      });
      return { output: [headers, ...output] };
    }
    
    const test0 = {
      data1: [[ "ID","name","Birthday","other"],["10","thomas","1992-03-17","empty"],["11","Emily","2000-03-03","empty"]],
      data2: [["other", "ID", "Balance", "city"],["hello", "10", "$4500", "New York"],["world", "10","$8","Brazil"]]
    };
    
    const test1 = {
      data1: [["ID","name","Birthday"],["10","thomas","1992-03-17"],["11","Emily","2000-03-03"]],
      data2: [["other","ID"],["x","10"],["y","11"]]
    };
    
    console.log(merge(test0, { Balance: '$0' }));
    console.log(merge(test1, { Balance: '$0' }));

    【讨论】:

    • 这个解决方案是不可扩展的,如果你添加像“Balance”这样的属性,它不会接受它们。
    • @karkael,我更新了代码以处理项目的任意排序。
    • 将此标记为已接受的答案,因为它非常适合我的给定场景。它很整洁,我可以重复使用该功能
    • 请在代码中添加 cmets 行 return i === 0 好吗? [...x, 'Balance'] : [...x, (data.data2.find((y) => y[idIdx2] === x[idIdx1]) || [])[balanceIdx2] | | '$0' 解释了代码的确切作用,因为我在理解这部分时遇到了一点困难: return i === 0 ? [...x, '平衡']
    • 非常感谢@jo_va。你真的很有帮助。
    【解决方案2】:
    const KEY_ID = "ID";
    
    var data = {
      "data1": [
        [ "ID", "name", "Birthday" ],
        [ "10", "thomas", "1992-03-17" ],
        [ "11", "Emily", "2000-03-03" ]
      ],
      "data2": [
        [ "Balance", "ID" ],
        [ "$4500", "10" ],
        [ "$1500", "13" ]
      ]
    }
    
    var merged = Object.keys(data).map(function (key) {
      var tmp = data[key].slice();
      var heads = tmp.shift();
      return tmp.map(function (item) {
        var row = {};
        heads.forEach(function (head, i) {
          row[head] = item[i];
        });
        return row;
      });
    }).flat().reduce(function (acc, row) {
      var found = acc.find(function (item) {
        return row[KEY_ID] === item[KEY_ID];
      })
      if (!found) {
        found = row;
        acc.push(found);
      } else {
        Object.keys(row).forEach(function (head) {
          found[head] = row[head];
        });
      }
      return acc;
    }, []);
    
    console.log(merged);
    

    此解决方案是可扩展的:如果您添加属性,它将扩展新格式。

    【讨论】:

      【解决方案3】:
      let a = { "data1": [ ... ],"data2": [ ...] }
      let r = a.data1.reduce((r,u,i)=>{
        if(i !== 0)
        {
          let entry = a.data2.filter((a)=> a[1]===u[0])
          r.push([...u,entry.length ? entry[0][0] : 0])
        }
         return r
      },[[
            "ID",
            "name",
            "Birthday",
            "Balance"
      ]])
      
      
      

      【讨论】:

        【解决方案4】:

        您可以将所有表操作抽象为类:

         function Table(array) {
           const [head, ...values] = array;
        
          const Entry =(entry) => ({
           get(key) { return entry[ head.indexOf(key) ]; },
           set(key, value) { entry[ head.indexOf(key) ] = value; }
          });
        
          return {
            index(name) {       
              const result = {};
              for(const value of values)
                result[ value[ head.indexOf(name) ] ] = Entry(value);
        
              return result;
            },
            *[Symbol.iterator]() {
              for(const row of values)
                 yield Entry(row);
             },
        
              addRow(key) { head.push(key); }
           };
         }
        

        可用作:

         const users = Table(obj.data1);
         const balances = Table(obj.data2);
        
         const balanceByID = balance.index("ID");
        
         users.addRow("Balance");
        
         for(const user of users)
           user.set("Balance", balanceByID[ user.get("ID") ].get("Balance"));
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-08-17
          • 2023-03-24
          • 2014-10-28
          • 2015-08-04
          • 1970-01-01
          • 1970-01-01
          • 2020-08-12
          • 1970-01-01
          相关资源
          最近更新 更多