Reputation: 23
I'll freely admit that Javascript is not my strongest language, and React Native is very new, so, there may be an obviously easy way to do this that I'm not seeing.
I've got an API that presents some transaction data in a simple structure:
[
{
"id": 1,
"title": "Apple Store",
"date": "2021-09-10",
"amount": "$100.00",
},
{
"id": 41,
"title": "Zulauf, Walter and Metz",
"date": "2021-09-10",
"amount": "$14.00",
},
{
"id": 9,
"title": "Aufderhar PLC",
"date": "2021-09-09",
"amount": "$78.00",
},
{
"id": 10,
"title": "Bayer and Sons",
"date": "2021-09-07",
"amount": "$67.00",
}
]
I want to present this data using a SectionList component, with the transactions in sections by date. My (likely crude) attempt to solve this was going to be to transform this data into the following structure:
[
{
"date": "2021-09-10",
"transactions": [
{
"id": 1,
"title": "Apple Store",
"date": "2021-09-10",
"amount": "$100.00",
},
{
"id": 41,
"title": "Zulauf, Walter and Metz",
"date": "2021-09-10",
"amount": "$14.00",
}
]
},
{
"date": "2021-09-09",
"transactions": [
{
"id": 9,
"title": "Aufderhar PLC",
"date": "2021-09-09",
"amount": "$78.00",
}
]
},
{
"date": "2021-09-07",
"transactions": [
{
"id": 10,
"title": "Bayer and Sons",
"date": "2021-09-07",
"amount": "$67.00",
}
]
}
]
But I'm honestly lost as to how to transform this data (or if there's a better way to solve this problem). I started by using Lodash's groupBy function, which seemed promising, but it looks like SectionList doesn't want an object, it wants an array.
Transforming the output of groupBy into an array straight off drops the keys and I've got grouped data but no clear value for the section header.
Again, there's probably some deviously simple way to address this, data comes in as a flat array all the time. I appreciate any guidance, assistance, or examples anybody can point me to.
Upvotes: 2
Views: 1902
Reputation: 2463
Here's a TypeScript utility function that I've written to do something similar:
// from https://stackoverflow.com/a/49752227
type KeyOfType<T, V> = keyof {
[P in keyof T as T[P] extends V? P: never]: any
};
// data[key] must be string, number, or symbol
export function groupBy<T>(data: T[], key: KeyOfType<T, string | number | symbol>) {
const collect: {[index: string | number | symbol]: T[]} = {};
for (let item of data) {
const key_value = item[key] as string | number | symbol;
if (key_value in collect) collect[key_value].push(item);
else collect[key_value] = [item];
}
return collect;
};
On the above data:
const data = [
{id: 1, title: 'Apple Store', date: '2021-09-10', amount: '$100.00'},
{id: 41, title: 'Zulauf, Walter and Metz', date: '2021-09-10', amount: '$14.00'},
{id: 9, title: 'Aufderhar PLC', date: '2021-09-09', amount: '$78.00'},
{id: 10, title: 'Bayer and Sons', date: '2021-09-07', amount: '$67.00'},
];
groupBy(data, 'date');
// yields:
{
'2021-09-07': [{id: 10, title: 'Bayer and Sons', date: '2021-09-07', amount: '$67.00'}],
'2021-09-09': [{id: 9, title: 'Aufderhar PLC', date: '2021-09-09', amount: '$78.00'}],
'2021-09-10': [
{id: 1, title: 'Apple Store', date: '2021-09-10', amount: '$100.00'},
{id: 41, title: 'Zulauf, Walter and Metz', date: '2021-09-10', amount: '$14.00'},
],
};
For multiple keys:
type Indexable = string | number | symbol;
export function multiGroupBy<T>(data: T[], ...keys: KeyOfType<T, Indexable>[]) {
const collect_keys: Indexable[][] = [];
const collect_values: T[][] = [];
for (let item of data) {
const key_value: Indexable[] = [];
for (let key of keys) {
key_value.push(item[key] as Indexable);
}
let key_ix = collect_keys.indexOf(key_value);
if (key_ix == -1) {
key_ix = collect_keys.length;
collect_keys.push(key_value);
collect_values.push([item]);
} else collect_values[key_ix].push(item);
}
return [collect_keys, collect_values];
}
Upvotes: 0
Reputation: 427
you could use loadash
var result = _(data)
.groupBy(item => item.date)
.map((value, key) => ({date: key, transactions: value}))
.value();
Upvotes: 0
Reputation: 193037
With lodash you can group by the date
then map to the required form:
const input = [{"id":1,"title":"Apple Store","date":"2021-09-10","amount":"$100.00"},{"id":41,"title":"Zulauf, Walter and Metz","date":"2021-09-10","amount":"$14.00"},{"id":9,"title":"Aufderhar PLC","date":"2021-09-09","amount":"$78.00"},{"id":10,"title":"Bayer and Sons","date":"2021-09-07","amount":"$67.00"}];
const result = _.map(
_.groupBy(input, 'date'),
(transactions, date) => ({ date, transactions })
)
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>
Upvotes: 0
Reputation: 22412
simply
const data =
[ { id: 1, title: 'Apple Store', date: '2021-09-10', amount: '$100.00' }
, { id: 41, title: 'Zulauf, Walter and Metz', date: '2021-09-10', amount: '$14.00' }
, { id: 9, title: 'Aufderhar PLC', date: '2021-09-09', amount: '$78.00' }
, { id: 10, title: 'Bayer and Sons', date: '2021-09-07', amount: '$67.00' }
]
const res = Object.entries(data.reduce((r,{id,title,date,amount})=>
{
r[date] = r[date] ?? []
r[date].push({id,title,date,amount})
return r
},{})).map(([k,v])=>({date:k,transactions:v}))
console.log( res )
.as-console-wrapper { max-height: 100% !important; top: 0 }
Upvotes: 0
Reputation: 12894
const input = [
{
"id": 1,
"title": "Apple Store",
"date": "2021-09-10",
"amount": "$100.00",
},
{
"id": 41,
"title": "Zulauf, Walter and Metz",
"date": "2021-09-10",
"amount": "$14.00",
},
{
"id": 9,
"title": "Aufderhar PLC",
"date": "2021-09-09",
"amount": "$78.00",
},
{
"id": 10,
"title": "Bayer and Sons",
"date": "2021-09-07",
"amount": "$67.00",
}
]
const result = input.reduce((accum, current)=> {
let dateGroup = accum.find(x => x.date === current.date);
if(!dateGroup) {
dateGroup = { date: current.date, transactions: [] }
accum.push(dateGroup);
}
dateGroup.transactions.push(current);
return accum;
}, []);
console.log(result)
Given an array, whenever your result is expecting to have same number of elements, use map
, but since your result has different number of elements, use reduce
as shown above. The idea is by having reduce
, loop over each element, see if you can find the element, and push the current element into the list
Upvotes: 5
Reputation: 2815
The lodash groupBy
just helps you with group data, you should process grouped data by converting it into your format.
const input = [
{
"id": 1,
"title": "Apple Store",
"date": "2021-09-10",
"amount": "$100.00",
},
{
"id": 41,
"title": "Zulauf, Walter and Metz",
"date": "2021-09-10",
"amount": "$14.00",
},
{
"id": 9,
"title": "Aufderhar PLC",
"date": "2021-09-09",
"amount": "$78.00",
},
{
"id": 10,
"title": "Bayer and Sons",
"date": "2021-09-07",
"amount": "$67.00",
}
];
const groupedArray = _.groupBy(input, "date");
let result = [];
for (const [key, value] of Object.entries(groupedArray)) {
result.push({
'date': key,
'transactions': value
})
}
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>
Upvotes: 0