使用 Ramda 将两个数组与两个不同的键组合在一起
Combine two arrays with two different keys with Ramda
我是 Ramda 和柯里化的新手,但想组合两个不同的数组。鉴于:
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}
];
我查看了文档,where
、intersection
和 merge
似乎是可以使用的。但是 intersection
和 merge
需要相同的密钥。 where
似乎是门票,但我仍然不确定如何告诉它我想要两个不同的键具有相同的值。
所以我认为我可以使用 forEach
、find
和 equals
中的一个或多个来镜像 POJS 方式。这是我的想法(到目前为止没有 intersection
或 where
用法):
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 方法。
可以使用 R.indexBy
, R.mergeWith
, and R.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)));
});
你想要的很可能会用到生成器。像这样:
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
函数以采用任意生成器,并将组合回调作为练习留给 reader。
当然有比惰性序列更紧凑的方法来解决这个问题,但它相当短,而且几乎肯定比重复搜索第二个数组以查找匹配项更高效,而且它远没有维护和递增两个单独的索引变量到一次完成。
由于根据您的评论总有匹配项,您可以按上述方式排序然后执行此操作:
let results = R.zip(arr1, arr2, (a, b) => Object.assign({}, a, b));
既然你想
" try a plain Javascript approach first."
这是一个 native JavaScript 替代解决方案,使用 Array.concat
、Array.find
、Array.indexOf
、Array.map
, Object.keys
和 Object.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
}
]
我是 Ramda 和柯里化的新手,但想组合两个不同的数组。鉴于:
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}
];
我查看了文档,where
、intersection
和 merge
似乎是可以使用的。但是 intersection
和 merge
需要相同的密钥。 where
似乎是门票,但我仍然不确定如何告诉它我想要两个不同的键具有相同的值。
所以我认为我可以使用 forEach
、find
和 equals
中的一个或多个来镜像 POJS 方式。这是我的想法(到目前为止没有 intersection
或 where
用法):
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 方法。
可以使用 R.indexBy
, R.mergeWith
, and R.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)));
});
你想要的很可能会用到生成器。像这样:
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
函数以采用任意生成器,并将组合回调作为练习留给 reader。
当然有比惰性序列更紧凑的方法来解决这个问题,但它相当短,而且几乎肯定比重复搜索第二个数组以查找匹配项更高效,而且它远没有维护和递增两个单独的索引变量到一次完成。
由于根据您的评论总有匹配项,您可以按上述方式排序然后执行此操作:
let results = R.zip(arr1, arr2, (a, b) => Object.assign({}, a, b));
既然你想
" try a plain Javascript approach first."
这是一个 native JavaScript 替代解决方案,使用 Array.concat
、Array.find
、Array.indexOf
、Array.map
, Object.keys
和 Object.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
}
]