Reputation: 1325
I have an array with the following values:
let orders = [
{n: 0, orderId: null, lat: 49.396315, lng: 15.609607, type: "start"},
{n: 2.5, orderId: 26889, lat: 48.98951, lng: 14.45937, type: "odes"},
{n: 9, orderId: 26969, lat: 50.0823536, lng: 12.3791268, type: "odes"},
{n: 9, orderId: 26995, lat: 50.0823536, lng: 12.3791268, type: "odes"},
{n: 31, orderId: null, lat: 50.7343366, lng: 15.0501002, type: "end"},
{n: 31, orderId: 26969, lat: 50.7343366, lng: 15.0501002, type: "prij"},
{n: 31, orderId: 26995, lat: 50.7343366, lng: 15.0501002, type: "prij"},
];
and I would like to have following result:
[
{n: 0, orderId: null, lat: 49.396315, lng: 15.609607, type: "start"},
{n: 2.5, orderId: 26889, lat: 48.98951, lng: 14.45937, type: "odes"},
{n: 9, orderId: [26969,26995], lat: 50.0823536, lng: 12.3791268, type: ["odes", "odes"]},
{n: 31, orderId: [null,26969,26995], lat: 50.7343366, lng: 15.0501002, type: ["end", "prij", "prij"]},
]
Basically, I want to merge values if n
, lat
and long
are the same,
any ideas on how to elegantly do this?
Thanks in advance
Upvotes: 1
Views: 67
Reputation: 22361
Array reduce can do that:
let orders =
[ { n: 0, orderId: null, lat: 49.396315, lng: 15.609607, type: 'start' }
, { n: 2.5, orderId: 26889, lat: 48.98951, lng: 14.45937, type: 'odes' }
, { n: 9, orderId: 26969, lat: 50.0823536, lng: 12.3791268, type: 'odes' }
, { n: 9, orderId: 26995, lat: 50.0823536, lng: 12.3791268, type: 'odes' }
, { n: 31, orderId: null, lat: 50.7343366, lng: 15.0501002, type: 'end' }
, { n: 31, orderId: 26969, lat: 50.7343366, lng: 15.0501002, type: 'prij' }
, { n: 31, orderId: 26995, lat: 50.7343366, lng: 15.0501002, type: 'prij' }
]
let res = orders.reduce((a,c,i,t)=>
{
if ( i // is equivalent to test (i> 0)
&& c.n === t[i-1].n
&& c.lat === t[i-1].lat
&& c.lgn === t[i-1].lgn )
{
let el = a[a.length-1] // last accumulator element
if (!Array.isArray( el.orderId ))
{ // change elements to array type
el.orderId = [ el.orderId ]
el.type = [ el.type ]
}
el.orderId.push(c.orderId) // add new values on
el.type.push(c.type)
}
else
a.push({...c}) // this one is the first with the keys combinations
return a
}
,[]) // answer initialisation with an empty array
console.log( res )
.as-console-wrapper { max-height: 100% !important; top: 0; }
If you don't want to create a new array, but just "cleaning" your original one, do:
let orders =
[ { n: 0, orderId: null, lat: 49.396315, lng: 15.609607, type: 'start' }
, { n: 2.5, orderId: 26889, lat: 48.98951, lng: 14.45937, type: 'odes' }
, { n: 9, orderId: 26969, lat: 50.0823536, lng: 12.3791268, type: 'odes' }
, { n: 9, orderId: 26995, lat: 50.0823536, lng: 12.3791268, type: 'odes' }
, { n: 31, orderId: null, lat: 50.7343366, lng: 15.0501002, type: 'end' }
, { n: 31, orderId: 26969, lat: 50.7343366, lng: 15.0501002, type: 'prij' }
, { n: 31, orderId: 26995, lat: 50.7343366, lng: 15.0501002, type: 'prij' }
]
for (let i=orders.length; (--i>0); ) // for i = orders.length-1 to 1
{
let el_c = orders[i] // pointers on current
, el_p = orders[i-1] // and previous array elements
;
if ( el_c.n === el_p.n
&& el_c.lat === el_p.lat
&& el_c.lng === el_p.lng ) // if same keys
{
el_p.orderId = [ el_p.orderId, el_c.orderId ].flat()
el_p.type = [ el_p.type, el_c.type ].flat()
orders.splice(i,1) // remove duplicate
} }
console.log( orders )
.as-console-wrapper { max-height: 100% !important; top: 0; }
Upvotes: 1
Reputation: 296
let orders = [
{ n: 0, orderId: null, lat: 49.396315, lng: 15.609607, type: "start" },
{ n: 2.5, orderId: 26889, lat: 48.98951, lng: 14.45937, type: "odes" },
{ n: 9, orderId: 26969, lat: 50.0823536, lng: 12.3791268, type: "odes" },
{ n: 9, orderId: 26995, lat: 50.0823536, lng: 12.3791268, type: "odes" },
{ n: 31, orderId: null, lat: 50.7343366, lng: 15.0501002, type: "end" },
{ n: 31, orderId: 26969, lat: 50.7343366, lng: 15.0501002, type: "prij" },
{ n: 31, orderId: 26995, lat: 50.7343366, lng: 15.0501002, type: "prij" }
];
let map = new Map();
orders.forEach((record) => {
let key = `n: ${record.n}, lat: ${record.lat}, lng: ${record.lng}`;
if (map.has(key)) {
let data = map.get(key);
data.push(record);
map.set(key, data);
} else {
map.set(key, [record]);
}
});
const nOrders = [];
map.forEach((value, key) => {
nOrders.push({
n: value[0].n,
lat: value[0].lat,
lng: value[0].lng,
orderId:
value.length === 1
? value[0].orderId
: value.map((entry) => entry.orderId),
type: value.length === 1 ? value[0].type : value.map((entry) => entry.type)
});
});
console.log(nOrders);
Upvotes: 1
Reputation: 2562
A simple naive solution consist of using a combined key, like ${n}-${lat}-${lng}
. I added '-' separator as it seems to be absent of n/lat/lng.
const results = {};
orders.forEach( elem => {
const key = `${elem.n}-${elem.lat}-${elem.lng}`;
//Already present, just add type and orderId
//Values can be duplicate, but you don't talk about that
if ( result[key] ) {
results[key].type.push( elem.type );
results[key].orderId.push( elem.orderId );
} else {
results[key] = {
n: elem.n,
orderId: [elem.orderId],
lat: elem.lat,
lng: elem.lng,
type: [elem.type]
};
}
});
Using the .reduce method of Array could be better, you should give a look.
Upvotes: 1
Reputation: 66218
You can take advantage of Array.prototype.reduce
, but some tweaking of the internal logic is required since the grouped properties can be string/number or an array thereof.
In the reduce callback, you can attempt to search for an existing entry by the grouping criteria, which you say it should be n
, lat
and lng
. If an entry is not found, you simply push the current item into your accumulator.
If an entry is found, then you need to perform some logic to convert the pre-existing string/number value into an array, and then append a new value to it.
See proof-of-concept code below:
let orders = [
{n: 0, orderId: null, lat: 49.396315, lng: 15.609607, type: "start"},
{n: 2.5, orderId: 26889, lat: 48.98951, lng: 14.45937, type: "odes"},
{n: 9, orderId: 26969, lat: 50.0823536, lng: 12.3791268, type: "odes"},
{n: 9, orderId: 26995, lat: 50.0823536, lng: 12.3791268, type: "odes"},
{n: 31, orderId: null, lat: 50.7343366, lng: 15.0501002, type: "end"},
{n: 31, orderId: 26969, lat: 50.7343366, lng: 15.0501002, type: "prij"},
{n: 31, orderId: 26995, lat: 50.7343366, lng: 15.0501002, type: "prij"},
];
// Receives a maybe array and pushes a new entry into it
function pushNewEntry(target, entry) {
if (!Array.isArray(target)) {
return [target, entry];
} else {
target.push(entry);
return target;
}
}
const groupedOrders = orders.reduce((acc, cur) => {
const { n, orderId, lat, lng, type } = cur;
// Find existing entry based on matching `n`, `lat`, and `lng`
const existingEntry = acc.find(x => {
return x.n === n && x.lat === lat && x.lng === lng;
});
if (!existingEntry) {
acc.push(cur);
} else {
existingEntry.orderId = pushNewEntry(existingEntry.orderId, orderId);
existingEntry.type = pushNewEntry(existingEntry.type, type);
}
return acc;
}, []);
console.log(groupedOrders);
Upvotes: 1