【问题标题】:Combine two arrays with two different keys with Ramda使用 Ramda 将两个具有两个不同键的数组组合在一起
【发布时间】:2016-06-03 01:39:26
【问题描述】:

我是 Ramda 和 currying 的新手,但想组合两个不同的数组。给定:

var array1 = [
 {_id: 0, x: 10},
 {_id: 1, x: 30}
];

var array2 = [
  {UUID: 0, y: 20},
  {UUID: 1, y: 60}
];

我想加入他们_id === UUID 以获得类似的东西:

var result = [
  {_id: 0, UUID: 0, x: 10, y: 20},
  {_id: 1, UUID: 1, x: 30, y: 60}
];

我查看了文档,whereintersectionmerge 似乎是可以使用的。但是intersectionmerge 期望相同的密钥。 where 似乎是票,但我仍然不确定如何告诉它我希望两个不同的键具有相同的值。

所以我想我可以使用 forEachfindequals 中的一个或多个来镜像 POJS 方式。这就是我的想法(目前没有使用 intersectionwhere):

import r from 'ramda';
var result = 
  r.forEach(
    r.find(
      r.equals(
        r.prop('UUID', r._),
        r.prop('_id', r._)
      ), data, metadata);

我被困在如何检查两个数组中的单独键(UUID_id),同时保持功能符号。我相信我做的一切都错了,但我的想法很糟糕,我会先尝试一个简单的 Javascript 方法。

【问题讨论】:

  • 答案很大程度上取决于每次是否有匹配且没有间隙。如果是这样,请使用 sort 和 zip/reduce。
  • @Nick,我可以建议一个可行的原生 javascript 解决方案
  • @JaredSmith 每次都会有一个匹配,并且没有重复/冲突的键。
  • @Nick 看看我更新的答案。使用 Ramda,它是一条线。

标签: javascript arrays ramda.js


【解决方案1】:

可以使用R.indexByR.mergeWithR.merge

//  propMerge :: String -> String -> Array Object -> Array Object -> Array Object
var propMerge = R.curry(function(k1, k2, xs1, xs2) {
  return R.values(R.mergeWith(R.merge,
                              R.indexBy(R.prop(k1), xs1),
                              R.indexBy(R.prop(k2), xs2)));
});

【讨论】:

    【解决方案2】:

    既然你想

    " 首先尝试简单的 Javascript 方法。"

    这是一个 native JavaScript 替代解决方案,使用 Array.concatArray.findArray.indexOfArray.mapObject.keysObject.assign 函数:

    var keys = ['_id', 'UUID'], result = {};
    
    array1.concat(array2).forEach(function(obj){
        var value = obj[Object.keys(obj).find((v) => keys.indexOf(v) !== -1 )],
            props = Object.keys(obj);  // array of property names of the current object
    
        result[value] = result[value] || obj;
        if (Object.keys(result[value]).indexOf(props[0]) === -1) {
            Object.assign(result[value], obj);  // "merging" two objects
        }
    }, result);
    result = Object.keys(result).map((k) => result[k]);
    
    console.log(JSON.stringify(result, 0, 4));
    

    输出:

    [
        {
            "_id": 0,
            "x": 10,
            "UUID": 0,
            "y": 20
        },
        {
            "_id": 1,
            "x": 30,
            "UUID": 1,
            "y": 60
        }
    ]
    

    【讨论】:

      【解决方案3】:

      你想要的很可能会用到generators。像这样:

      arr1.sort((a, b) => a._id - b._id);
      arr2.sort((a, b) => a.UUID - b.UUID);
      
      let step1 = arr1[Symbol.iterator]();
      let step2 = arr2[Symbol.iterator]();
      
      let zipSeq = (first, second) => {
        let done = false, result = [];
        while (!done) {
          let obj = first.next();
          let check = second.next();
          while (check.value.UUID !== obj.value._id && !check.done) {
            check = second.next(); // make sure we account for non-sequential
          }
          result.push(Object.assign({}, obj.value, check.value));
          done = obj.done || check.done;
        }
        return result;
      };
      
      let mixed = zipSeq(step1, step2);
      

      泛化zipSeq 函数以采用任意生成器,并将组合回调作为练习留给读者。

      肯定有比惰性序列更紧凑的方法来解决这个问题,但它非常短,几乎可以肯定比重复搜索第二个数组以查找匹配项更高效,而且它远不如维护和递增两个单独的索引变量来完成这两个任务一口气。

      由于您的评论总是有匹配的,您可以按上述排序,然后执行以下操作:

      let results = R.zip(arr1, arr2, (a, b) => Object.assign({}, a, b));
      

      【讨论】:

        猜你喜欢
        • 2022-01-24
        • 1970-01-01
        • 2017-03-15
        • 1970-01-01
        • 2022-01-17
        • 2012-08-16
        • 2019-09-25
        • 2016-04-16
        • 2015-01-19
        相关资源
        最近更新 更多