JavaScript | Object Grouping

javascript | Object grouping

Try with something like this:

function groupBy(collection, property) {
var i = 0, val, index,
values = [], result = [];
for (; i < collection.length; i++) {
val = collection[i][property];
index = values.indexOf(val);
if (index > -1)
result[index].push(collection[i]);
else {
values.push(val);
result.push([collection[i]]);
}
}
return result;
}

var obj = groupBy(list, "group");

Keep in mind that Array.prototype.indexOf isn't defined in IE8 and older, but there are common polyfills for that.

How can I group an array of objects by key?

Timo's answer is how I would do it. Simple _.groupBy, and allow some duplications in the objects in the grouped structure.

However the OP also asked for the duplicate make keys to be removed. If you wanted to go all the way:

var grouped = _.mapValues(_.groupBy(cars, 'make'),
clist => clist.map(car => _.omit(car, 'make')));

console.log(grouped);

Yields:

{ audi:
[ { model: 'r8', year: '2012' },
{ model: 'rs5', year: '2013' } ],
ford:
[ { model: 'mustang', year: '2012' },
{ model: 'fusion', year: '2015' } ],
kia:
[ { model: 'optima', year: '2012' } ]
}

If you wanted to do this using Underscore.js, note that its version of _.mapValues is called _.mapObject.

Most efficient method to groupby on an array of objects

If you want to avoid external libraries, you can concisely implement a vanilla version of groupBy() like so:

var groupBy = function(xs, key) {
return xs.reduce(function(rv, x) {
(rv[x[key]] = rv[x[key]] || []).push(x);
return rv;
}, {});
};

console.log(groupBy(['one', 'two', 'three'], 'length'));

// => {"3": ["one", "two"], "5": ["three"]}

Grouping nested object properties

Here's my take. A series of nested for for...in loops. Tried to optimize for readability.

const object = {
1: { one: { a: 5, b: 6, c: 7, d: 8 } },
2: { one: { a: 6, b: 9, c: 10, d: 12, e: 1 } },
3: { one: { a: 3, b: 4, c: 9 } },
};

const result = {};

for (const group in object) {
for (const num in object[group]) {
if (!result[num]) {
result[num] = {};
}
for (const letter in object[group][num]) {
if (!result[num][letter]) {
result[num][letter] = [];
}
result[num][letter].push(object[group][num][letter])
}
}
}

console.log(result)

How to group array of objects by certain property values

A back to the future answer :

Not yet supported by lot of browsers but will come soon (Stage 3 for TC39) and already available in polyfill core-js) is the new groupBy method on the array object.

This will allows you to do it directly like this :

employees.groupBy(employee => employee.company);

or even :

employees.groupBy(({company}) => company);

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/groupBy

Javascript - grouping an array and then sorting the grouped result based on length

From my above comment ...

"In case the OP depends on key insertion order (though it would even work) of an object (because this is what the OP is asking for) then the OP's entire data handle approach is at question. What one could do instead ... create a sorted array of object-items from the former object of grouped entries."

The next provided solution does exactly what already got proposed.

In order to achieve the intermediate grouping goal one would reduce the given data-structure into an object of grouped entries (each entry holding an array of some of the former data-array items.

Each of the entries now can be mapped into an own object of the still unsorted result array which within a last step will be sorted by either each object's sole array-value length-property or by a locale comparison of the single property names (keys).

function groupAndCollectBySameKeyValue({ key, result }, item) {
const groupValue = item[key];
(result[groupValue] ??= []).push(item);
return { key, result };
}

var dataArr = [
{ permalink: 'link', subreddit: 'laravel' },
{ permalink: 'link', subreddit: 'mac' },
{ permalink: 'link', subreddit: 'ArtisanVideos' },
{ permalink: 'link', subreddit: 'laravel' },
{ permalink: 'link', subreddit: 'ArtisanVideos' },
{ permalink: 'link', subreddit: 'chrome' },
{ permalink: 'link', subreddit: 'ArtisanVideos' },
{ permalink: 'link', subreddit: 'laravel' },
];
console.log(
dataArr
.reduce(groupAndCollectBySameKeyValue, {
key: 'subreddit',
result: {},
})
.result
);
console.log(
Object
.entries(
dataArr
.reduce(groupAndCollectBySameKeyValue, {
key: 'subreddit',
result: {},
})
.result
)
// create object from grouped entry (key-value pair).
.map(([key, value]) => ({ [key]: value }))
.sort((a, b) =>
// ... either by array length ...
Object.values(b)[0].length - Object.values(a)[0].length
// ... or by locale alphanumeric precedence.
|| Object.keys(a)[0].localeCompare(Object.keys(b)[0])
)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }

Grouping an array of objects and assign new combined value to each object

I'd say the most efficient way to do it would be to create an object which maps school to an array of names. Then map the initial array:

var initialArr= [
{name:"A", school:"LFM"},
{name:"B", school:"LFM"},
{name:"C", school:"PBE"},
{name:"D", school:"LFM"},
{name:"E", school:"BPE"},
{name:"F", school:"LFM"}
];

var schoolObj = initialArr.reduce((a, { name, school }) => {
a[school] = (a[school] || []);
a[school].push(name);
return a;
}, {});

var expectedResult = initialArr.map(e => {
e.alumni = schoolObj[e.school].join("-");
return e;
});

console.log(expectedResult);

Grouping Array element using two properties

Here is what you are looking for, without using of any additional libraries:

const data = [{"id":"myid","base":{"orderNumber":"0500332","marketPlaceOrderCode":"","creationDate":"2022-06-14T10:49:10Z","source":"sfcc","brands":["KI", "SA"],"country":"BG","status":"new","totalEuro":12,"currency":"BGN","units":1,"coupons":null,"shipping":{"id":"BG01","name":"Speedy COD","status":"not_shipped"}},"psp":{"name":"payu","method":null,"status":null},"tms":null},{"id":"DEC-00500331","base":{"orderNumber":"id2","marketPlaceOrderCode":"","creationDate":"2022-06-14T10:41:29Z","source":"sfcc","brands":["DEC"],"country":"UK","status":"new","totalEuro":57,"currency":"GBP","units":1,"coupons":null,"shipping":{"id":"ECA_DPD_ST","name":"Standard shipping","status":"not_shipped"}},"psp":{"name":"adyen","method":null,"status":"paid"},"tms":null}];

const rawResult = normalizeData(data);
console.log(makeItReadable(rawResult));

function normalizeData(data) {
const result = {};

data.forEach((order) => {
const orderData = order.base;

// add country to result (if not exists)
if (!result[orderData.country]) {
result[orderData.country] = {};
}

orderData.brands.forEach((brand) => {
// add brand to exact country (if not exists)
if (!result[orderData.country][brand]) {
result[orderData.country][brand] = {};
}

// add status to exact brand and country (if not exists)
if (!result[orderData.country][brand][orderData.status]) {
result[orderData.country][brand][orderData.status] = 0;
}

// increment status count
++result[orderData.country][brand][orderData.status];
});
});

return result;
}

function makeItReadable(rawData) {
const readableResult = [];
Object.keys(rawData).map((country) => {
Object.keys(rawData[country]).map((brand) => {
readableResult.push({country, brand, ...rawData[country][brand]});
});
});

return readableResult;
}

This code will give you the following result:

[
{ country: 'BG', brand: 'KI', new: 1 },
{ country: 'BG', brand: 'SA', new: 1 },
{ country: 'UK', brand: 'DEC', new: 1 }
]

Grouping values into one array of objects from two objects based on differing keys

You can loop over the keys of the ingredients object and create the desired array by slicing out the ingredient number and looking for the corresponding measure for that number.

const 
ingredients = { strIngredient1: "Light rum", strIngredient2: "Lime", strIngredient3: "Sugar", strIngredient4: "Mint", strIngredient5: "Soda water" },
measurements = { strMeasure1: "2-3 oz", strMeasure2: "Juice of 1", strMeasure3: "2 tsp", strMeasure4: "2-4" },
result = Object.keys(ingredients).map((k) => ({
ingredient: ingredients[k],
measure: measurements[`strMeasure${k.slice(13)}`] ?? "",
}));

console.log(result);


Related Topics



Leave a reply



Submit