I have such array with a lot of objects:
[
{
startAt: "2016-01-01 11:35:00",
fromCurrencyId: "a49cd579-18ea-44cb-8117-86428b64a27a",
toCurrencyId: "c5a0c46c-c5b5-49a5-9a16-4a829269583e"
},
{
startAt: "2016-01-01 11:40:00",
fromCurrencyId: "a49cd579-18ea-44cb-8117-86428b64a27a",
toCurrencyId: "c5a0c46c-c5b5-49a5-9a16-4a829269583e"
},
{
startAt: "2016-01-01 12:00:00",
fromCurrencyId: "c5a0c46c-c5b5-49a5-9a16-4a829269583e",
toCurrencyId: "5491dfe0-7d61-407d-b642-7fd3ec905302"
},
{
startAt: "2016-01-01 12:40:00",
fromCurrencyId: "c5a0c46c-c5b5-49a5-9a16-4a829269583e",
toCurrencyId: "5491dfe0-7d61-407d-b642-7fd3ec905302"
},
{
startAt: "2016-01-01 11:40:00",
fromCurrencyId: "a49cd579-18ea-44cb-8117-86428b64a27a",
toCurrencyId: "5491dfe0-7d61-407d-b642-7fd3ec905302"
},
...
]
I would like to split this array into sub-arrays by fields: 'fromCurrencyId', 'toCurrencyId':
[
[
{
startAt: "2016-01-01 11:35:00",
fromCurrencyId: "a49cd579-18ea-44cb-8117-86428b64a27a",
toCurrencyId: "c5a0c46c-c5b5-49a5-9a16-4a829269583e"
},
{
startAt: "2016-01-01 11:40:00",
fromCurrencyId: "a49cd579-18ea-44cb-8117-86428b64a27a",
toCurrencyId: "c5a0c46c-c5b5-49a5-9a16-4a829269583e"
}
],
[
{
startAt: "2016-01-01 12:00:00",
fromCurrencyId: "c5a0c46c-c5b5-49a5-9a16-4a829269583e",
toCurrencyId: "5491dfe0-7d61-407d-b642-7fd3ec905302"
},
{
startAt: "2016-01-01 12:40:00",
fromCurrencyId: "c5a0c46c-c5b5-49a5-9a16-4a829269583e",
toCurrencyId: "5491dfe0-7d61-407d-b642-7fd3ec905302"
}
],
[
{
startAt: "2016-01-01 11:40:00",
fromCurrencyId: "a49cd579-18ea-44cb-8117-86428b64a27a",
toCurrencyId: "5491dfe0-7d61-407d-b642-7fd3ec905302"
}
]
]
I've tried using lodash group by and native methods, but I don't understand how to do it correctly yet. I hope for your help.
My last attempt:
const props = ['fromCurrencyId', 'toCurrencyId']
const a = _.groupBy(data, function(note){
return _.find(_.pick(note, props));
});
where data is my array. And next, I wanted to delete the keys from the object and thereby get my new array
CodePudding user response:
Your groupBy method should return a consistent "key" that you want to group similar objects on. Your current approach doesn't do that, as your _.find()
is not being used on any data (you're only passing one argument to it).
Instead, you can do this without lodash. Below I've used reduce to create a Map
(similar to an object). Each key in the map is a unique key that combines the fromCurrencyId
with the toCurrencyId
properties, and stores a value as an array of objects with the same currency id combination.
See working example below (and code comments for more details):
const arr = [ { startAt: "2016-01-01 11:35:00", fromCurrencyId: "a49cd579-18ea-44cb-8117-86428b64a27a", toCurrencyId: "c5a0c46c-c5b5-49a5-9a16-4a829269583e" }, { startAt: "2016-01-01 11:40:00", fromCurrencyId: "a49cd579-18ea-44cb-8117-86428b64a27a", toCurrencyId: "c5a0c46c-c5b5-49a5-9a16-4a829269583e" }, { startAt: "2016-01-01 12:00:00", fromCurrencyId: "c5a0c46c-c5b5-49a5-9a16-4a829269583e", toCurrencyId: "5491dfe0-7d61-407d-b642-7fd3ec905302" }, { startAt: "2016-01-01 12:40:00", fromCurrencyId: "c5a0c46c-c5b5-49a5-9a16-4a829269583e", toCurrencyId: "5491dfe0-7d61-407d-b642-7fd3ec905302" }, { startAt: "2016-01-01 11:40:00", fromCurrencyId: "a49cd579-18ea-44cb-8117-86428b64a27a", toCurrencyId: "5491dfe0-7d61-407d-b642-7fd3ec905302" } ];
const res = Array.from(arr.reduce((map, obj) => {
const key = `${obj.fromCurrencyId}-${obj.toCurrencyId}`; // create the key
const curr = map.get(key) || []; // get the grouped objects if the key already exists, otherwise creattee an empty array
return map.set(key, curr.concat(obj)); // add the current object to the array, at our currency id key
}, new Map).values());
console.log(res);
One approach using lodash is to use _.groupBy()
and then use _.at()
to grab the values at fromCurrencyId
and toCurrencyId
(_.at()
is like your _.pick()
, but it returns an array of values instead of an object). This array of values is automatically converted into a string (via an implicit .toString()
call) when it's used as a key for the object _.groupBy()
returns. You can then take the _.values()
of the object to get just the grouped values:
const arr = [ { startAt: "2016-01-01 11:35:00", fromCurrencyId: "a49cd579-18ea-44cb-8117-86428b64a27a", toCurrencyId: "c5a0c46c-c5b5-49a5-9a16-4a829269583e" }, { startAt: "2016-01-01 11:40:00", fromCurrencyId: "a49cd579-18ea-44cb-8117-86428b64a27a", toCurrencyId: "c5a0c46c-c5b5-49a5-9a16-4a829269583e" }, { startAt: "2016-01-01 12:00:00", fromCurrencyId: "c5a0c46c-c5b5-49a5-9a16-4a829269583e", toCurrencyId: "5491dfe0-7d61-407d-b642-7fd3ec905302" }, { startAt: "2016-01-01 12:40:00", fromCurrencyId: "c5a0c46c-c5b5-49a5-9a16-4a829269583e", toCurrencyId: "5491dfe0-7d61-407d-b642-7fd3ec905302" }, { startAt: "2016-01-01 11:40:00", fromCurrencyId: "a49cd579-18ea-44cb-8117-86428b64a27a", toCurrencyId: "5491dfe0-7d61-407d-b642-7fd3ec905302" } ];
const props = ['fromCurrencyId', 'toCurrencyId'];
const a = _.values(_.groupBy(arr, note => _.at(note, props), "-"));
console.log(a);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js" integrity="sha512-WFN04846sdKMIP5LKNphMaWzU7YpMyCU245etK3g/2ARYbPK9Ub18eG ljU96qKRCWh quCY7yefSmlkQw1ANQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
CodePudding user response:
here is my attend. i use some
to check if the sub-arrays already exist in the result. if not, i use filter
to find the matching fromCurrencyId
and toCurrencyId
and then create a sub-arrays and push it to the result.
const data = [
{
startAt: "2016-01-01 11:35:00",
fromCurrencyId: "a49cd579-18ea-44cb-8117-86428b64a27a",
toCurrencyId: "c5a0c46c-c5b5-49a5-9a16-4a829269583e"
},
{
startAt: "2016-01-01 11:40:00",
fromCurrencyId: "a49cd579-18ea-44cb-8117-86428b64a27a",
toCurrencyId: "c5a0c46c-c5b5-49a5-9a16-4a829269583e"
},
{
startAt: "2016-01-01 12:00:00",
fromCurrencyId: "c5a0c46c-c5b5-49a5-9a16-4a829269583e",
toCurrencyId: "5491dfe0-7d61-407d-b642-7fd3ec905302"
},
{
startAt: "2016-01-01 12:40:00",
fromCurrencyId: "c5a0c46c-c5b5-49a5-9a16-4a829269583e",
toCurrencyId: "5491dfe0-7d61-407d-b642-7fd3ec905302"
},
{
startAt: "2016-01-01 11:40:00",
fromCurrencyId: "a49cd579-18ea-44cb-8117-86428b64a27a",
toCurrencyId: "5491dfe0-7d61-407d-b642-7fd3ec905302"
},
]
const result = data.reduce((p, c, _, arr) => {
if (!p.some(p => p.some(p => p.fromCurrencyId === c.fromCurrencyId && p.toCurrencyId === c.toCurrencyId))) {
p.push(arr.filter(a => a.fromCurrencyId === c.fromCurrencyId && a.toCurrencyId === c.toCurrencyId));
}
return p
}, [])
console.log(result);
CodePudding user response:
lodash
may be able to do it in fewer steps but I wanted to demonstrate an answer without using external libraries (for now)
See the inline comments for reasoning:
// key name we're targetting
const targetIds = ["fromCurrencyId", "toCurrencyId"];
// your data
const data = [{
startAt: "2016-01-01 11:35:00",
fromCurrencyId: "a49cd579-18ea-44cb-8117-86428b64a27a",
toCurrencyId: "c5a0c46c-c5b5-49a5-9a16-4a829269583e"
},
{
startAt: "2016-01-01 11:40:00",
fromCurrencyId: "a49cd579-18ea-44cb-8117-86428b64a27a",
toCurrencyId: "c5a0c46c-c5b5-49a5-9a16-4a829269583e"
},
{
startAt: "2016-01-01 12:00:00",
fromCurrencyId: "c5a0c46c-c5b5-49a5-9a16-4a829269583e",
toCurrencyId: "5491dfe0-7d61-407d-b642-7fd3ec905302"
},
{
startAt: "2016-01-01 12:40:00",
fromCurrencyId: "c5a0c46c-c5b5-49a5-9a16-4a829269583e",
toCurrencyId: "5491dfe0-7d61-407d-b642-7fd3ec905302"
},
{
startAt: "2016-01-01 11:40:00",
fromCurrencyId: "a49cd579-18ea-44cb-8117-86428b64a27a",
toCurrencyId: "5491dfe0-7d61-407d-b642-7fd3ec905302"
},
]
// A set of the unique values for the given key name
// `.join` is used to create a unique string made up of the values of teh targetIds
const uniq = Array.from(new Set(data.map(item => targetIds.map(target => item[target]).join(","))));
// console.log(uniq)
// Map over the Array, and then for each item
// e.g. "5491dfe0-7d61-407d-b642-7fd3ec905302"
// Filter out your original data for each item to get an Array of Arrays
// `.split` is then used in combination with `every` to find the _values_ of the targetIds
const subData = uniq.map(combinedValue => data.filter(d => combinedValue.split(",").every((value, index) => d[targetIds[index]] === value)));
console.log(subData)
Edit: I have modified my answer and rectified my mistake