Group by Array and Add Field and Sub Array in Main Array

Group by array and add field and sub array in main array

This is a snippet I wrote for these kind of situations. You can add this functionality to all of your arrays:

Object.defineProperty(Array.prototype, 'group', {
enumerable: false,
value: function (key) {
var map = {};
this.forEach(function (e) {
var k = key(e);
map[k] = map[k] || [];
map[k].push(e);
});
return Object.keys(map).map(function (k) {
return {key: k, data: map[k]};
});
}
});

You can use it like this. You can just pass a function which defines how you want to group your data.

var newArray = arr.group(function (item) {
return item.optionName;
});

Working Fiddle

If you need, you can replace {key: k, data: map[k]} with {Name: k, Data: map[k]}.


This is also more compact ES6 version of the code above:

Object.defineProperty(Array.prototype, 'group', {
enumerable: false,
value: function (key) {
let map = {};
this.map(e => ({k: key(e), d: e})).forEach(e => {
map[e.k] = map[e.k] || [];
map[e.k].push(e.d);
});
return Object.keys(map).map(k => ({key: k, data: map[k]}));
}
});

Use it like this:

let newArray = arr.group(item => item.optionName))

Group array of javascript objects based on value into there own sub array of objects

You could use a closure over a hash table for the same email address and their items.

var data = [{ email: "alex@test.com", fn: "Alex", sn: "McPherson", phone: "01233xxxxx", hours: "40", rate: "20", amount: "200", vat: "60", agency: "test", start: "08/06/2017", end: "10/06/2017" }, { email: "mike@test.com", fn: "Mike", sn: "Mann", phone: "01233xxxxx", hours: "50", rate: "70", amount: "500", vat: "90", agency: "test", start: "08/06/2017", end: "10/06/2017" }, { email: "fred@test.com", fn: "Fred", sn: "Frogg", phone: "01233xxxxx", hours: "80", rate: "90", amount: "800", vat: "100", agency: "test", start: "08/06/2017", end: "10/06/2017" }, { email: "alex@test.com", fn: "Alex", sn: "McPherson", phone: "01233xxxxx", hours: "90", rate: "30", amount: "900", vat: "120", agency: "test", start: "08/06/2017", end: "10/06/2017" }],    result = data.reduce(function (hash) {        return function (r, o) {            if (!hash[o.email]) {                hash[o.email] = [];                r.push(hash[o.email]);            }            hash[o.email].push(o)            return r;        };    }(Object.create(null)), []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Group rows in an associative array of associative arrays by column value and preserve the original first level keys

$arr = array();

foreach ($old_arr as $key => $item) {
$arr[$item['id']][$key] = $item;
}

ksort($arr, SORT_NUMERIC);

How to group subarrays by a column value?

There is no native one, just use a loop.

$result = array();
foreach ($data as $element) {
$result[$element['id']][] = $element;
}

How to group keys and values of an (sub)array and sum its values using PHP?

I'm surprised at all the long and complicated answers. However, the initial foreach to model your data to something manageable is needed. After that you just need to do a really simple array_walk.

<?php
$result = array();
foreach ($array as $el) {
if (!array_key_exists($el[0], $result)) {
$result[$el[0]] = array();
}
$result[$el[0]][] = $el[1];
}
array_walk($result, create_function('&$v,$k', '$v = array_sum($v) / count($v);'));
?>

Result:

Array
(
[ALFA] => 187
[BETA] => 167
[ZETA] => 254
[GAMA] => 175.5
)

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"]}

Manipulate an array of objects inside another array

You can go with the following approach:

array1 =
[
{
"first": "A",
"second": [
"one"
]
},
{
"first": "A",
"second": [
"three"
]
},
{
"first": "C",
"second": [
"four"
]
},
{
"first": "D",
"second": [
"one"
]
},
{
"first": "C",
"second": [
"three"
]
},
]

var array2 = []

array1.forEach(function(item) {
var existing = array2.filter(function(v, i) {
return v.first == item.first;
});
if (existing.length) {
var existingIndex = array2.indexOf(existing[0]);
array2[existingIndex].second = array2[existingIndex].second.concat(item.second);
} else {
if (typeof item.second == 'string')
item.second = [item.second];
array2.push(item);
}
});

console.log(array2);

Group objects by multiple properties in array then sum up their values

Use Array#reduce with a helper object to group similar objects. For each object, check if the combined shape and color exists in the helper. If it doesn't, add to the helper using Object#assign to create a copy of the object, and push to the array. If it does, add it's values to used and instances.

var arr = [{"shape":"square","color":"red","used":1,"instances":1},{"shape":"square","color":"red","used":2,"instances":1},{"shape":"circle","color":"blue","used":0,"instances":0},{"shape":"square","color":"blue","used":4,"instances":4},{"shape":"circle","color":"red","used":1,"instances":1},{"shape":"circle","color":"red","used":1,"instances":0},{"shape":"square","color":"blue","used":4,"instances":5},{"shape":"square","color":"red","used":2,"instances":1}];
var helper = {};var result = arr.reduce(function(r, o) { var key = o.shape + '-' + o.color; if(!helper[key]) { helper[key] = Object.assign({}, o); // create a copy of o r.push(helper[key]); } else { helper[key].used += o.used; helper[key].instances += o.instances; }
return r;}, []);
console.log(result);

multiple grouping of documents with nested array in mongodb

You can use an aggregation query, but it will impact on performance and speed of response, there are two options, one using $unwind and another using $accumulator operator,

using $accumulator:

  • $group by category and field
  • $accumulator to do custom JavaScript logic and merge items array, you can improve and update as per your requirement
  • $project to show required fields
db.collection.aggregate([
{
$group: {
_id: {
category: "$category",
field: "$field"
},
items: {
$accumulator: {
init: function() { return []; },
accumulate: function(items1, items2) {
return items1.concat(items2);
},
accumulateArgs: ["$items"],
merge: function(items1, items2) {
return items1.concat(items2);
},
finalize: function(state) {
var items = {}, finalItems = [];
state.forEach(function(item) {
if (items[item.title]) {
items[item.title].value.push(item.value);
}
else {
item.value = [item.value];
items[item.title] = item;
}
});
for (var i in items) {
finalItems.push(items[i]);
}
return finalItems;
},
lang: "js"
}
}
}
},
{
$project: {
_id: 0,
category: "$_id.category",
field: "$_id.field",
items: 1
}
}
])

using $unwind: (not recommended)

  • $unwind deconstruct the items array
  • $group by category, field and item title and construct the array if item values
  • $group by category and field and construct the items array with title and value
  • $project to show required fields
db.collection.aggregate([
{ $unwind: "$items" },
{
$group: {
_id: {
category: "$category",
field: "$field",
title: "$items.title"
},
value: { $push: "$items.value" }
}
},
{
$group: {
_id: {
category: "$_id.category",
field: "$_id.field"
},
items: {
$push: {
title: "$_id.title",
value: "$value"
}
}
}
},
{
$project: {
_id: 0,
category: "$_id.category",
field: "$_id.field",
items: 1
}
}
])

Playground



Related Topics



Leave a reply



Submit