Grouping array of objects by multiple keys - javascript

I feel embarrassed for asking this question as I should know how to figure it out, but I'm spinning my wheels on grouping an array of objects by multiple keys.
Here's the data:
[
{
"car": "audi",
"type": "A6",
"style": "Avant",
"year": "1996"
},
{
"car": "audi",
"type": "A4",
"style": "2",
"year": "2006"
},
{
"car": "audi",
"type": "A4",
"style": "L W12",
"year": "2006"
},
{
"car": "audi",
"type": "80",
"style": "GLE",
"year": "1975"
},
{
"car": "audi",
"type": "A6",
"style": "Avant L",
"year": "1996"
},
{
"car": "audi",
"type": "A6",
"style": "3.2 Multitronic",
"year": "2006"
},
]
What I've been trying to generate with little success is the following:
[{
"audi": [{
"1996": {
"A6": ["Avant, Avant L"]
}
}, {
"2006": }
"A6": ["3.2 Multitronic"],
"A4": ["L W12", "2"]
}
}
....
}]
The schema is:
{
"car1": [{
"year1": {
"style1": ["trim1", "trim2"],
"style2": ["trim1", "trim2"]
},
"year1": {
"style1": ["trim1", "trim2"],
"style2": ["trim1", "trim2"]
}
}],
"car2": [{
"year1": {
"style1": ["trim1", "trim2"],
"style2": ["trim1", "trim2"]
},
"year2": {
"style1": ["trim1", "trim2"],
"style2": ["trim1", "trim2"]
}
}]
}
I've tried the following with lodash
let result = _.chain(carData)
.groupBy('car')
.toPairs()
.map(function(curr) {
return _.zipObject(['car', 'year'], curr);
})
.value();
This gets me part of the way, but I end up with incomplete data when it comes to the styles and types for each year of the car.

You could use a hash object and a nested approach for the given properties.
var data = [{ car: "audi", type: "A6", style: "Avant", year: 1996 }, { car: "audi", type: "A4", style: 2, year: 2006 }, { car: "audi", type: "A4", style: "L W12", year: 2006 }, { car: "audi", type: 80, style: "GLE", year: 1975 }, { car: "audi", type: "A6", style: "Avant L", year: 1996 }, { car: "audi", type: "A6", style: "3.2 Multitronic", year: 2006 }],
keys = ['car', 'year', 'type'],
result = [];
data.forEach(function (a) {
keys.reduce(function (r, k) {
var o = {};
if (!r[a[k]]) {
r[a[k]] = { _: [] };
o[a[k]] = r[a[k]]._;
r._.push(o);
}
return r[a[k]];
}, this)._.push(a.style);
}, { _: result });
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Here's a (slightly verbose) solution that generates exactly the JSON object shape you wanted and groups by unlimited keys:
var cars = [{
"car": "audi",
"type": "A6",
"style": "Avant",
"year": "1996"
}, {
"car": "audi",
"type": "A4",
"style": "2",
"year": "2006"
}, {
"car": "audi",
"type": "A4",
"style": "L W12",
"year": "2006"
}, {
"car": "audi",
"type": "80",
"style": "GLE",
"year": "1975"
}, {
"car": "audi",
"type": "A6",
"style": "Avant L",
"year": "1996"
}, {
"car": "audi",
"type": "A6",
"style": "3.2 Multitronic",
"year": "2006"
}, ];
function groupBy(list, prop) {
return list.reduce((groupped, item) => {
var key = item[prop];
delete item[prop];
if (groupped.hasOwnProperty(key)) {
groupped[key].push(item);
} else {
groupped[key] = [item];
}
return groupped
}, {});
}
function groupSubKeys(obj, properties, propIndex) {
var grouppedObj = groupBy(obj, properties[propIndex]);
Object.keys(grouppedObj).forEach((key) => {
if (propIndex < properties.length - 2) {
grouppedObj[key] = groupSubKeys(grouppedObj[key], properties, propIndex + 1);
} else {
grouppedObj[key] = grouppedObj[key].map(item => item[properties[propIndex + 1]])
}
});
return grouppedObj;
}
function groupByProperties(list, properties) {
return groupSubKeys(list, properties, 0);
}
console.log(groupByProperties(cars, ['car', 'year', 'type', 'style']));
Here's a running example:
http://codepen.io/rarmatei/pen/evmBOo

const groupBy = function groupBy(list, properties, propertyIndex) {
// current property index
let i = propertyIndex === undefined ? 0 : propertyIndex;
// group by
let grouppedObj = list.reduce((acc, obj) => {
let groupedValue = obj[properties[i]];
if (!groupedValue) {
return acc;
}
if (!acc[groupedValue]) {
acc[groupedValue] = [];
}
acc[groupedValue].push({ ...obj, groupBy: properties.join(",") });
return acc;
}, {});
// group by nested
const keys = Object.keys(grouppedObj);
if (i === properties.length - 1) {
return grouppedObj;
}
keys.forEach((key) => {
grouppedObj[key] = groupBy(grouppedObj[key], properties, i + 1);
});
return grouppedObj;
};
const data =[
{
"year": "2021",
"cabin": "1",
"months": ["1", "2"]
},
{
"year": "2021",
"cabin": "1",
"months": ["4"]
},
{
"year": "2021",
"cabin": "2",
"months": ["1", "2"]
},
{
"year": "2022",
"cabin": "1",
"months": ["1", "2"]
},
{
"year": "2022",
"cabin": "1",
"months": ["4"]
},
{
"year": "2022",
"cabin": "2",
"months": ["1", "2"]
}
];
const results=groupBy(data, ["year", "cabin"]);
console.log(results);

Related

Using Reduce to rearrange an Object of Arrays

I am trying to get the below output from the array using reduce, however, I can't wrap my head about some parts on how reduce behave , appreciate some explanation so I can fully grasp it.
final goal is after reducing the result into a single array, removing duplicate objects based on the vch_number
Reduce function
const result = car.reduce((acc,vch)=>{
const temp = {...acc,[vch.name]:vch.Vehciles}
for (const [key, value] of Object.entries(temp)){
const fillterd = value.map(item => {
item.status = key
return item
})
}
return temp
}
,{})
console.log(result)
// final desired output vs current output
current = { available:
[ { make: 'bwm',
model: 'i8',
year: 2000,
vch_number: 51511,
status: 'available' },
{ make: 'bwm',
model: 'i8',
year: 2020,
vch_number: 51541,
status: 'available' } ],
parked:
[ { make: 'bwm',
model: 'i8',
year: 2000,
vch_number: 51510,
status: 'parked' } ],
service:
[ { make: 'bwm',
model: 'i8',
year: 2000,
vch_number: 51510,
status: 'service' } ] }
desired = [
{ make: 'bwm',
model: 'i8',
year: 2000,
vch_number: 51511,
status: 'available' },
{ make: 'bwm',
model: 'i8',
year: 2020,
vch_number: 51541,
status: 'available' },
{ make: 'bwm',
model: 'i8',
year: 2000,
vch_number: 51510,
status: 'parked' } ,
{ make: 'bwm',
model: 'i8',
year: 2000,
vch_number: 51510,
status: 'service' }
]
// Original API array
const car = [
{
"name": "available",
"Vehciles": [
{
"make": "bwm",
"model": "i8",
"year": 2000,
"vch_number": 51511,
},
{
"make": "bwm",
"model": "i8",
"year": 2020,
"vch_number": 51541,
}
]
},
{
"name": "parked",
"Vehciles": [
{
"make": "bwm",
"model": "i8",
"year": 2000,
"vch_number": 51510,
}
]
},
{
"name": "service",
"Vehciles": [
{
"make": "bwm",
"model": "i8",
"year": 2000,
"vch_number": 51510,
}
]
}
]
First problem is your using a {} as the second argument (the so called accumulator) in the .reduce() function. You'll want to pass an empty array [].
Second off all you have the Vehciles array inside those objects so you have to perform one more transformation inside.
more about reducers:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
I think the key is to wrap your head around the initialValue and the accumulator and how it relates to the currentValue when it comes to Array.reduce()
I've whipped up this code:
const car = [
{
"name": "available",
"Vehciles": [
{
"make": "bwm",
"model": "i8",
"year": 2000,
"vch_number": 51511,
},
{
"make": "bwm",
"model": "i8",
"year": 2020,
"vch_number": 51541,
}
]
},
{
"name": "parked",
"Vehciles": [
{
"make": "bwm",
"model": "i8",
"year": 2000,
"vch_number": 51510,
}
]
},
{
"name": "service",
"Vehciles": [
{
"make": "bwm",
"model": "i8",
"year": 2000,
"vch_number": 51510,
}
]
}
];
const result = car.reduce((acc,vch)=>{
const cars = vch.Vehciles.map(vehicle => {
const temp = {
status: vch.name,
...vehicle
};
return temp;
}).reduce((carAcc, car) => {
carAcc.push(car);
return carAcc;
}, acc);
return acc;
}, []);
console.log(result)
You could map the objects and check with a Set.
const
data = [{ name: "available", Vehciles: [{ make: "bwm", model: "i8", year: 2000, vch_number: 51511 }, { make: "bwm", model: "i8", year: 2020, vch_number: 51541 }] }, { name: "parked", Vehciles: [{ make: "bwm", model: "i8", year: 2000, vch_number: 51510 }] }, { name: "service", Vehciles: [{ make: "bwm", model: "i8", year: 2000, vch_number: 51510 }] }],
result = data.flatMap(
(seen => ({ name: status, Vehciles }) => Vehciles.flatMap(o => seen.has(o.vch_number)
? []
: (seen.add(o.vch_number), { ...o, status })
))
(new Set)
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Object transformation using a functional approach

I am reading a simple data set from a data.txt file. I would like to take this data and transform it into a specific object as per my example below. I have managed to get it into a somewhat usable JSON object but this is not ideal. I have included an example of the desired object.
Here is my app.js file:
let output = fs.readFileSync('./data.txt', 'UTF8')
.trim()
.split('\r\n')
.map((line) => line.split(';'))
.reduce((customers, line) => {
customers.push({
name: line[0],
product: [{
item: line[1],
serial: line[2],
year: line[3]
}]
})
return customers
}, [])
console.log(JSON.stringify(output, null, 2))
This currently the above NodeJs code returns the following array object:
[
{
"name": "Nancy",
"product": [
{
"item": "Macbook Pro",
"serial": "A34D05980FCD4303",
"year": "2019"
}
]
},
{
"name": "Nancy",
"product": [
{
"item": "iPad",
"serial": "O0403X3028423C92",
"year": "2015"
}
]
},
{
"name": "Nancy",
"product": [
{
"item": "iPhone",
"serial": "X3830238S3309230",
"year": "2017"
}
]
},
{
"name": "John",
"product": [
{
"item": "Macbook Pro",
"serial": "X2020J393983H380",
"year": "2013"
}
]
},
{
"name": "John",
"product": [
{
"item": "iPhone",
"serial": "X38320093X032309",
"year": "2015"
}
]
},
{
"name": "fluffikins",
"product": [
{
"item": "iMac",
"serial": "F392D392033X3232",
"year": "2013"
}
]
},
{
"name": "fluffikins",
"product": [
{
"item": "iPad",
"serial": "FE322230D3223S21",
"year": "2011"
}
]
}
]
What I am trying to do is get the below object returned - ideally still following the same functional approach:
[
{
"name": "Nancy",
"product": [
{
"item": "Macbook Pro",
"serial": "A34D05980FCD4303",
"year": "2019"
},
{
"item": "iPad",
"serial": "O0403X3028423C92",
"year": "2015"
},
{
"item": "iPhone",
"serial": "X3830238S3309230",
"year": "2017"
}
]
},
{
"name": "John",
"product": [
{
"item": "Macbook Pro",
"serial": "X2020J393983H380",
"year": "2013"
},
{
"item": "iPhone",
"serial": "X38320093X032309",
"year": "2015"
}
]
},
{
"name": "fluffikins",
"product": [
{
"item": "iMac",
"serial": "F392D392033X3232",
"year": "2013"
},
{
"item": "iPad",
"serial": "FE322230D3223S21",
"year": "2011"
}
]
}
]
Here is my mock data set that lives in data.txt
Nancy;Macbook Pro;A34D05980FCD4303;2019
Nancy;iPad;O0403X3028423C92;2015
Nancy;iPhone;X3830238S3309230;2017
John;Macbook Pro;X2020J393983H380;2013
John;iPhone;X38320093X032309;2015
fluffikins;iMac;F392D392033X3232;2013
fluffikins;iPad;FE322230D3223S21;2011
Instead of an array you can use Map in reduce as accumulator, use name as key in Map and club value of all keys, finally just get the values Map to get desired output
const data = `Nancy;Macbook Pro;A34D05980FCD4303;2019
Nancy;iPad;O0403X3028423C92;2015
Nancy;iPhone;X3830238S3309230;2017
John;Macbook Pro;X2020J393983H380;2013
John;iPhone;X38320093X032309;2015
fluffikins;iMac;F392D392033X3232;2013
fluffikins;iPad;FE322230D3223S21;2011`
const final = data.split('\n')
.map(v => v.split(';'))
.reduce((op, [name, item, serial, year]) => {
let obj = { item, serial, year }
if (op.has(name)) {
op.get(name).products.push(obj)
} else{
op.set(name,{name, products:[obj]})
}
return op
}, new Map())
console.log([...final.values()])
Here is a "functional version" that utilizes a Map to find duplicates in O(1):
(map => (
fs.readFileSync('./data.txt', 'UTF8')
.trim()
.split('\r\n')
.map((line) => line.split(';'))
.forEach(([name, item, serial, year]) =>
map.has(name)
? map.get(name).product.push({ item, serial, year })
: map.set(name, { name, product: [{ item, serial, year }] })
),
[...map.values()]
)(new Map)
But seriously, whats so bad about imperative style?:
const customers = new Map;
const entries = fs.readFileSync('./data.txt', 'UTF8')
.trim()
.split('\r\n');
for(const entry of entries) {
const [name, item, serial, year] = entry.split(";");
const product = { item, serial, year };
if(customers.has(name)) {
customers.get(name).product.push(product);
} else customers.set(name, { name, product: [product] });
}
const result = [...customers.values()];
You can modify the .reduce function to only add a new item to the array if there isn't one with that name. If there is, just add the product to that item's product array.
const data = `Nancy;Macbook Pro;A34D05980FCD4303;2019
Nancy;iPad;O0403X3028423C92;2015
Nancy;iPhone;X3830238S3309230;2017
John;Macbook Pro;X2020J393983H380;2013
John;iPhone;X38320093X032309;2015
fluffikins;iMac;F392D392033X3232;2013
fluffikins;iPad;FE322230D3223S21;2011`;
const result = data.trim()
.split('\n')
.map((line) => line.split(';'))
.reduce((customers, line) => {
const product = {
item: line[1],
serial: line[2],
year: line[3]
};
const customer = customers.find(({
name
}) => name === line[0]);
if (customer) {
customer.product.push(product);
} else {
customers.push({
name: line[0],
product: [product]
});
}
return customers
}, []);
console.log(result);

What is the most performant way to convert an Array of Object to an Object with unique keys

I am trying to figure out the most performant Javascript way to convert an array of objects, into an object with unique keys and an array full of objects as the value.
For Example:
const array = [
{ "name": "greg", "year": "2000" },
{ "name": "john", "year": "2002" },
{ "name": "bob", "year": "2005" },
{ "name": "ned", "year": "2000" },
{ "name": "pam", "year": "2000" },
];
I would like this converted to:
{
"2000": [
{ "name": "greg", "year": "2000" },
{ "name": "ned", "year": "2000" },
{ "name": "pam", "year": "2000" }
],
"2002": [ { "name": "john", "year": "2002" } ],
"2005": [ { "name": "bob", "year": "2005" } ],
}
As of now, this is what I've done so far:
let yearsObj = {};
for (let i=0; i<array.length; i++) {
if (!yearsObj[array[i].year]) {
yearsObj[array[i].year] = [];
}
yearsObj[array[i].year].push(array[i]);
}
you can use a more elegant way to do it by using array's reduce function
// # impl
const group = key => array =>
array.reduce(
(objectsByKeyValue, obj) => ({
...objectsByKeyValue,
[obj[key]]: (objectsByKeyValue[obj[key]] || []).concat(obj)
}),
{}
);
// # usage
console.log(
JSON.stringify({
byYear: group(array),
}, null, 1)
);
// output
VM278:1 {
"carsByBrand": {
"2000": [
{
"name": "greg",
"year": "2000"
},
{
"name": "ned",
"year": "2000"
},
{
"name": "pam",
"year": "2000"
}
],
"2002": [
{
"name": "john",
"year": "2002"
}
],
"2005": [
{
"name": "bob",
"year": "2005"
}
]
}
}
It could be as simple as that Object.fromEntries(array.map(obj => [obj.year,obj])) even it is not exactly what you need, but talking about performance it is way slower than all proposed, so i'm giving it as an bad example of showing how the short statement is not always the fastest.
Your way seems to be the fastest taking about performance.
Run the snippet below to see the actual timing.
// common
let array = [
{ "name": "greg", "year": "2000" },
{ "name": "john", "year": "2002" },
{ "name": "bob", "year": "2005" },
{ "name": "ned", "year": "2000" },
{ "name": "pam", "year": "2000" },
];
// simple as a statement way
console.time();
console.log(Object.fromEntries(array.map(obj => [obj.year,obj])));
console.timeEnd();
// using .reduce way
console.time();
const result = array.reduce((prev, curr) => {
const { year } = curr;
if (prev[year]) {
prev[year].push(curr);
} else {
prev[year] = [curr];
}
return prev;
}, {});
console.log(result);
console.timeEnd();
// your way
console.time();
let yearsObj = {};
for (let i=0; i<array.length; i++) {
if (!yearsObj[array[i].year]) {
yearsObj[array[i].year] = [];
}
yearsObj[array[i].year].push(array[i]);
}
console.log(yearsObj);
console.timeEnd();
A for loop (imperative style) like you have is likely to be the fastest in most situations. However, in this case you are not likely to see much of a difference. One thing you could do to improve the code in your example is to get the array length before the for loop and assign it to the variable, so that it's not calculated every iteration of the loop.
const yearsObj = {};
const arrayLength = array.length; // Only calculate array length once
for (let i=0; i<arrayLength; i++) {
if (!yearsObj[array[i].year]) {
yearsObj[array[i].year] = [];
}
yearsObj[array[i].year].push(array[i]);
}
In this situation, my preference would be to use Array.reduce(). It is more readable and the performance difference will be negligible.
const arr = [
{ name: 'greg', year: '2000' },
{ name: 'john', year: '2002' },
{ name: 'bob', year: '2005' },
{ name: 'ned', year: '2000' },
{ name: 'pam', year: '2000' },
];
const result = arr.reduce((prev, curr) => {
const { year } = curr;
if (prev[year]) {
prev[year].push(curr);
} else {
prev[year] = [curr];
}
return prev;
}, {});
/* Result:
{ '2000':
[ { name: 'greg', year: '2000' },
{ name: 'ned', year: '2000' },
{ name: 'pam', year: '2000' } ],
'2002': [ { name: 'john', year: '2002' } ],
'2005': [ { name: 'bob', year: '2005' } ] }
*/

Summing up value in array of objects

[
{
"id": {
"extId": "112",
"year": "2000"
},
"Count": 1
},
{
"id": {
"extId": "113",
"year": "2001"
},
"Count": 446
},
{
"id": {
"extId": "115",
"year": "2000"
},
"Count": 742
}, ...
]
I have a very long array of objects. I need to sum up the count based on the year. For e.g, I would like something like [{2000: 743}, {2001: 446},...].
I am not sure how to proceed with that in javascript. Should I loop through every object in the array and check for the year or is there some javascript function which can make this simpler.
Thanks.
You can use Array.reduce():
let countByYear = objects.reduce((acc, next) => {
acc[next.id.year] = (acc[next.id.year] || 0) + next.Count;
return acc;
}, {});
Note, this will produce a different structure from your example (because I read your question too sloppily):
{
2000: 743,
2001: 446
}
However I would say this is easier to work with than [ { 2000: 743 }, { 2001: 446 } ], since in that case you have an array of objects, that each have a single key, and you have no way of knowing what that key is, which I'd imagine makes it really difficult to iterate over them.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
You can use reduce:
arr.reduce((result, current) => {
result.push({[current.year]: current.Count});
return result
}, [])
This will give you this structure [{2000: 743}, {2001: 44}] and you can even do arr.filter(filterFn) first if you need to filter only certain years
You could use a Map and take the key/values for an array of objects.
var data = [{ id: { extId: "112", year: "2000" }, Count: 1 }, { id: { extId: "113", year: "2001" }, Count: 446 }, { id: { extId: "115", year: "2000" }, Count: 742 }],
count = Array.from(
data.reduce(
(m, { id: { year }, Count }) => m.set(year, (m.get(year) || 0) + Count),
new Map
),
([year, count]) => ({ [year]: count })
);
console.log(count);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script>
var arr=[
{
"id": {
"extId": "112",
"year": "2000"
},
"Count": 1
},
{
"id": {
"extId": "113",
"year": "2001"
},
"Count": 446
},
{
"id": {
"extId": "115",
"year": "2000"
},
"Count": 742
}
];
var result=arr.reduce((result, current) => {
result.push({[current.id.year]: current.Count});
return result;
}, []);
console.log(result);
</script>
reduce will do the trick here for you:
var arr = [
{
"id": {
"extId": "112",
"year": "2000"
},
"Count": 1
},
{
"id": {
"extId": "113",
"year": "2001"
},
"Count": 446
},
{
"id": {
"extId": "115",
"year": "2000"
},
"Count": 742
},
{
"id": {
"extId": "116",
"year": "2001"
},
"Count": 44
}
];
let count = arr.reduce((acc, next) => {
acc[next.id.year] = (acc[next.id.year] || 0) + next.Count;
return acc;
}, {});
console.log(count);
ES6
You could use reduce() function to get required result.
DEMO
const data = [{"id": {"extId": "112","year": "2000"},"Count": 1},{"id": {"extId": "113","year": "2001"},"Count": 446},{"id": {"extId": "115","year": "2000"},"Count": 742}];
let result = data.reduce((r, {Count,id: {year}}) => {
r[year] = (r[year] || 0) + Count;
return r;
}, {});
console.log([result])
.as-console-wrapper {max-height: 100% !important;top: 0;}
var yearCount={};
var temp=[
{
"id": {
"extId": "112",
"year": "2000"
},
"Count": 1
},
{
"id": {
"extId": "113",
"year": "2001"
},
"Count": 446
},
{
"id": {
"extId": "115",
"year": "2000"
},
"Count": 742
}
];
temp.forEach(item=>{
var val=yearCount[item.id.year];
if (val){
yearCount[item.id.year]=val+item.Count;
}
else{
yearCount[item.id.year]=item.Count;
}
})
console.log(yearCount);

Create new array with another structure in Javascript

I want to create a new array based on an original array but with merged data.
Every name key need to have merged date+time (format: YYYY-MM-DD HH:MM) with merged scores. All unique datetimes need to be available as key for each name.
ARRAY ORIGINAL:
"data": [{
"name": "A",
"history": [{
"created": "2017-05-16 00:00:00",
"score": "1"
},
{
"created": "2017-05-16 00:01:10",
"score": "1"
},
{
"created": "2017-05-16 00:01:30",
"score": "1"
}
]
},
{
"name": "B",
"history": [{
"created": "2017-05-16 00:01:00",
"score": "1"
}]
}
]
ARRAY THAT I WANT:
{
[A]: {
"2017-05-16 00:00": 1,
"2017-05-16 00:01": 2
},
[B]: {
"2017-05-16 00:00": 0,
"2017-05-16 00:01": 1
}
}
I hope you guys can help me out. I can't even think of an efficiƫnt way to do this, unfortunately. I tried to solve this issue with 5 foreach statements with no luck :(
You could use two arrays for names and times as closure and generate for all names and times a property with zero value.
var data = { data: [{ name: "A", history: [{ created: "2017-05-16 00:00:00", score: "1" }, { created: "2017-05-16 00:01:10", score: "1" }, { created: "2017-05-16 00:01:30", score: "1" }] }, { name: "B", history: [{ created: "2017-05-16 00:01:00", score: "1" }] }] },
result = data.data.reduce(function (names, times) {
return function (r, a) {
if (!r[a.name]) {
r[a.name] = {};
times.forEach(function (time) {
r[a.name][time] = 0;
});
names.push(a.name);
}
a.history.forEach(function (o) {
var time = o.created.slice(0, 16);
if (times.indexOf(time) === -1) {
names.forEach(function (name) {
r[name][time] = 0;
});
times.push(time);
}
r[a.name][time] += +o.score;
});
return r;
};
}([], []), {});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You have to create an object not an array, As arrays cannot have a key-value pair in javascript. There is no associative array concept in javascript. You have to use objects in javascript for that.
Here is how you can do what you are trying to achieve using objects.
value = {
"data": [{
"name": "A",
"history": [{
"created": "2017-05-16 00:00:00",
"score": "1"
},
{
"created": "2017-05-16 00:01:10",
"score": "1"
},
{
"created": "2017-05-16 00:01:30",
"score": "1"
}
]},
{
"name": "B",
"history": [{
"created": "2017-05-16 00:01:00",
"score": "1"
}]
}]
};
var result ={};
value.data.forEach(function(v){
var score = {};
for(var i=0;i<v.history.length;i++){
score[v.history[i].created] = v.history[i].score;
}
result[v.name] = score;
});
console.log(result);
Now you can access data as result.A or result[A] and result.B or result[B]
SNIPPET
value = {
"data": [{
"name": "A",
"history": [{
"created": "2017-05-16 00:00:00",
"score": "1"
},
{
"created": "2017-05-16 00:01:10",
"score": "1"
},
{
"created": "2017-05-16 00:01:30",
"score": "1"
}
]
},
{
"name": "B",
"history": [{
"created": "2017-05-16 00:01:00",
"score": "1"
}]
}
]
};
var result = {};
value.data.forEach(function(v) {
var score = {};
for (var i = 0; i < v.history.length; i++) {
score[v.history[i].created] = v.history[i].score;
}
result[v.name] = score;
});
console.log(result);

Categories