admin管理员组文章数量:1301534
I'm new to Ramda and currying but would like to bine two different arrays. 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:
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. But intersection
and merge
expect the same key. 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.
So I figure I can do it mirroring the POJS way, using one or more of forEach
, find
, and equals
. Here's what I was thinking (no intersection
or where
usage so far):
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. I believe I'm going about it all wrong but my mind is rutted and I'll try a plain Javascript approach first.
I'm new to Ramda and currying but would like to bine two different arrays. 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:
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. But intersection
and merge
expect the same key. 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.
So I figure I can do it mirroring the POJS way, using one or more of forEach
, find
, and equals
. Here's what I was thinking (no intersection
or where
usage so far):
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. I believe I'm going about it all wrong but my mind is rutted and I'll try a plain Javascript approach first.
- The answer greatly depends on whether there is a match every time with no gaps. If so use sort and zip/reduce. – Jared Smith Commented Jun 2, 2016 at 16:30
- @Nick, I can suggest a working native javascript solution – RomanPerekhrest Commented Jun 2, 2016 at 17:05
- @JaredSmith There will be a match each time, as well as no duplicate/colliding keys. – Nick Commented Jun 2, 2016 at 17:35
- @Nick see my updated answer then. With Ramda its a one-liner. – Jared Smith Commented Jun 2, 2016 at 17:41
3 Answers
Reset to default 9One could use 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)));
});
Since you had in mind to
" try a plain Javascript approach first."
here is a native JavaScript alternative solution using Array.concat
, Array.find
, Array.indexOf
, Array.map
, Object.keys
and Object.assign
functions:
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
}
]
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 bining callback is left as an exercize to the reader.
There are certainly more pact 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 ment 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));
本文标签: javascriptCombine two arrays with two different keys with RamdaStack Overflow
版权声明:本文标题:javascript - Combine two arrays with two different keys with Ramda - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741619173a2388707.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论