简体   繁体   English

使用Ramda将两个具有两个不同键的数组组合在一起

[英]Combine two arrays with two different keys with Ramda

I'm new to Ramda and currying but would like to combine two different arrays. 我是Ramda和currying的新手,但想结合两个不同的数组。 Given: 鉴于:

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

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

I would like to join them where _id === UUID to get something like this: 我想在_id === UUID地方加入他们,得到这样的东西:

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

I looked at the docs and where , intersection , and merge seemed to be the ones to use. 我看了看文档, whereintersectionmerge似乎是要使用的文档。 But intersection and merge expect the same key. 但是intersectionmerge期望使用相同的键。 where seems to be the ticket, but I'm still not sure how to tell it that I want two different keys to have the same value. 似乎在where ,但是我仍然不确定如何告诉我我想要两个不同的键具有相同的值。

So I figure I can do it mirroring the POJS way, using one or more of forEach , find , and equals . 因此,我认为可以使用forEachfindequals一个或多个来镜像POJS方式。 Here's what I was thinking (no intersection or where usage so far): 下面是我在想什么(无intersectionwhere使用至今):

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

I'm stuck at just how to check for the separate keys ( UUID and _id ) from the two arrays while keeping the functional notation. 我只停留在如何从两个数组中检查单独的键( UUID_id ),同时又保留功能符号的情况下。 I believe I'm going about it all wrong but my mind is rutted and I'll try a plain Javascript approach first. 我相信我会做错所有的事情,但是我的想法很沮丧,我将首先尝试简单的Javascript方法。

One could use R.indexBy , R.mergeWith , and R.merge : 可以使用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)));
});

What you want is likely to use generators . 您想要的可能是使用生成器 Like so: 像这样:

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);

Generalizing the zipSeq function to take arbitrary generators and a combining callback is left as an exercize to the reader. 通用化zipSeq函数以采用任意生成器,并且将合并回调作为zipSeq留给读者。

There are certainly more compact ways to solve this than lazy sequences, but its pretty short and almost certainly more performant than repeatedly searching the second array for matches, and its far less imperative than maintaining and incrementing two separate indexing variables to do both in one pass. 解决此问题的方法肯定比惰性序列更紧凑,但是比重复搜索第二个数组的匹配项要短得多,而且几乎可以肯定是性能更高的,而且比维护和递增两个单独的索引变量来一次完成这两个过程要简单得多。

Since per your comment there are always matches, you can sort as above and then do this: 由于根据您的评论始终存在匹配项,因此您可以按上述进行排序,然后执行以下操作:

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

Since you had in mind to 既然你想到了

" try a plain Javascript approach first." “首先尝试使用简单的Javascript方法。”

here is a native JavaScript alternative solution using Array.concat , Array.find , Array.indexOf , Array.map , Object.keys and Object.assign functions: 这是使用Array.concatArray.findArray.indexOfArray.mapObject.keysObject.assign函数的原生 JavaScript替代解决方案:

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));

The output: 输出:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM