how to assign object in object - javascript

how to assign the object in object and filter the value which pass and fail;
the input is:
[
{
name: 'John',
score: 90,
time: 'evening'
},
{
name: 'Doni',
score: 68,
time: 'morning'
},
{
name: 'Jiu',
score: 50,
time: 'evening'
},
{
name: 'Shin',
score: 92,
time: 'morning'
},
];
and i want the output like this :
{
"evening": {
"pass": [
{
"name": "John",
"score": 90
}
],
"fail": [
{
"name": "jiu",
"score": 50
}
]
},
"morning": {
"pass": [
{
"name": "Shin",
"score": 92
}
],
"fail": [
{
"name": "Doni",
"score": 68
}
]
}
}
do we need to use Object.assign for this ? and how many loop we use for this ??
i do love to know how to add another string in the object beside that ouput,
thanks

There's a lot of ways to do this. The simplest is probably to make a base object that represent your empty results. Then loop over the students and fill the arrays:
let students = [{name: 'John',score: 90,time: 'evening'},{name: 'Doni',score: 68,time: 'morning'},{name: 'Jiu',score: 50,time: 'evening'},{name: 'Shin',score: 92,time: 'morning'},];
// Empty case
let base = {
"evening": {"pass": [], "fail": []},
"morning": {"pass": [], "fail": []}
}
const PASSING = 70
students.forEach(({name, score, time}) => {
let key = score >= PASSING ? 'pass' : 'fail'
base[time][key].push({name, score})
})
console.log(base)
This makes is easy to have empty arrays, which is probably what you want if there are no students in a particular category.
EDIT based on comment:
To support arbitrary times, you can just create the times on the object as you find them. reduce() is good for this, but you could also use a regular loop. For example with an added afternoon time:
let students = [{name: 'Mark',score: 95,time: 'afternoon'}, {name: 'John',score: 90,time: 'evening'},{name: 'Doni',score: 68,time: 'morning'},{name: 'Jiu',score: 50,time: 'evening'},{name: 'Shin',score: 92,time: 'morning'},];
const PASSING = 70
let result = students.reduce((obj, {name, score, time}) => {
if (!obj[time]) obj[time] = {'pass': [], 'fail': [] }
let key = score >= PASSING ? 'pass' : 'fail'
obj[time][key].push({name, score})
return obj
}, {})
console.log(result)

You can do something like this:
const data = [{ name: 'John', score: 90, time: 'evening' }, { name: 'Doni', score: 68, time: 'morning' }, { name: 'Jiu', score: 50, time: 'evening' }, { name: 'Shin', score: 92, time: 'morning' }, ];
const grp = (d, p) => d.reduce((r,c) => (r[c[p]] = [...r[c[p]] || [], c], r), {})
const grpV = (d, rng) => d.reduce((r,{name, score}) => {
let key = score > rng ? 'pass' : 'fail'
r[key] = [...r[key] || [], {name, score}]
return r
}, {})
const r = Object.entries(grp(data, 'time')).map(([k,v]) => ({[k]: grpV(v, 75)}))
console.log(r)
The idea is the group 2 times one on the time and 2nd on the score.
grp: function to group by a property (in this case 'time') which returns an object with 2 properties: evening and morning each of which is an array containing the classes.
grpV: function to group by value (in this case 75) which returns an object with 2 properties: pass and fail each of which is an array containing the classes.
On the end once we have those tools we are saying ... give me the entries of the grouped by time object and for each of the groups ... group by score.
Here how something like this could look like if we ware using lodash:
const data = [{ name: 'John', score: 90, time: 'evening' }, { name: 'Doni', score: 68, time: 'morning' }, { name: 'Jiu', score: 50, time: 'evening' }, { name: 'Shin', score: 92, time: 'morning' }, ];
const partition = (x, p) => _(x)
.partition(y => y.score > p)
.map((x,i) => ({ [i==0 ? 'pass': 'fail']: _.omit(x[0], 'time')}))
.value()
const r = _(data)
.groupBy('time')
.mapValues(x => partition(x, 75))
.value()
console.log(r)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
Adding it as an example since it does help with readability of what the ES6 example is doing to some extend.

I'm sure there are more elegant ways to do this. But this one is probably one of the simplest beginner-friendly ways you can go about this.
I loop through the input array, check the existence of the .time values as keys on the output object and create the pass and fail keys. Then evaluate the .score against the passingScore and push the necessary data to it.
Should be pretty easy to understand once you see and try the code below:
const data = [
{name: 'John',score: 90, time: 'evening'},
{name: 'Doni',score: 68, time: 'morning'},
{name: 'Jiu',score: 50, time: 'evening'},
{name: 'Shin',score: 92, time: 'morning'},
{name: 'Fubar',score: 75, time: 'noon'},
];
function formatData(data){
const passingScore = 75;
const output = {};
data.forEach(function(item){
if(!output[item.time]) output[item.time] = {pass: [], fail: []};
const stud = { name: item.name, score: item.score };
if(item.score >= passingScore) output[item.time]['pass'].push(stud)
else output[item.time]['fail'].push(stud)
});
return output;
}
console.log(formatData(data));

Related

Javascript: How would you get the highest rated product category based on these 2 arrays

Assuming I have 2 arrays:
const products = [
{
name: 'prod1',
category: 'Meat'
},
{
name: 'prod2',
category: 'Meat'
},
{
name: 'prod3',
category: 'Dairy'
}];
const rate = [
{
name: 'prod1',
rate: 23,
},
{
name: 'prod2',
rate: 36
},
{
name: 'prod3',
rate: 50,
}];
How would you get the category that has the highest sum rate? For example, prod1 and prod2 share the same category 'Meat" and hence the rate for meat is 36 + 23 = 59.
The way I thought about it is to create an adjusted Array of products where each entry will contain the rate from the second array and then I will create a result array and push an object of category and sumRate after iterating the adjustedArray.
So if the result Array has an object with category, I would adjust the sum and add the new rate, if not I'll create a new entry with category: rate.
Can we do this in a very optimal way?
As the OP probably knows, canonical grouping goes like this...
const prodsByCategory = products.reduce((acc, p) => {
let cat = p.category;
if (!acc[cat]) acc[cat] = [];
acc[cat].push(p);
return acc;
}, {});
Modify this a little to add the data which will be needed to optimize.
const prodsByCategory = products.reduce((acc, p) => {
let cat = p.category;
// instead of just an array, keep an array and a total
if (!acc[cat]) acc[cat] = { products: [], totalRate: 0 };
// instead of just pushing, push and increment total with a lookup
acc[cat].products.push(p);
acc[cat].totalRate += rateForProduct(p) || 0;
return acc;
}, {});
We need a lookup for rateForProduct, like this:
const rateForProduct = product => {
return rate.find(r => r.name === product.name)?.rate || 0;
}
That should produce an object keyed by category with values that have a prop called totalRate. Sort those entries so that the first one is maximized. Here's a demo...
const products = [{
name: 'prod1',
category: 'Meat'
},
{
name: 'prod2',
category: 'Meat'
},
{
name: 'prod3',
category: 'Dairy'
}
];
const rate = [{
name: 'prod1',
rate: 23,
},
{
name: 'prod2',
rate: 36
},
{
name: 'prod3',
rate: 50,
}
];
const rateForProduct = product => {
return rate.find(r => r.name === product.name)?.rate || 0;
}
const prodsByCategory = products.reduce((acc, p) => {
let cat = p.category;
if (!acc[cat]) acc[cat] = {
products: [],
totalRate: 0
};
acc[cat].products.push(p);
acc[cat].totalRate += rateForProduct(p);
return acc;
}, {});
const sortedEntries = Object.entries(prodsByCategory).sort((a, b) => b[1].totalRate - a[1].totalRate);
const bestEntry = {
category: sortedEntries[0][0],
rate: sortedEntries[0][1].totalRate
}
console.log(bestEntry);

How to merge 2 array of objects by id and date in Javascript?

This 2 arrays have multiple objects that has the the same ID but different dates
const names= [
{id:'1',name:'a',date:'1604616214'},
{id:'1',name:'Angel',date:'1604616215'},
{id:'2',name:'b',date:'2004616214'},
{id:'2',name:'Karen',date:'2004616215'},
{id:'3',name:'a',date:'3004616220'},
{id:'3',name:'Erik',date:'3004616221'}
]
const lastnames= [
{id:'1',lastname:'a',date:'4004616220'},
{id:'1',lastname:'Ferguson',date:'4004616221'},
{id:'2',lastname:'b',date:'5004616220'},
{id:'2',lastname:'Nixon',date:'5004616221'},
{id:'3',lastname:'a',date:'6004616222'},
{id:'3',lastname:'Richard',date:'6004616223'}
]
The data is in moment().unix() to create a number "easy to compare"
I want to create a Third array that merge the 2 arrays and create objects with the same id and the last updated date object.
The output should be something like this
const third = [
{id:'1',name:'Angel',lastname:'Ferguson'},
{id:'2',name:'Karen',lastname:'Nixon'},
{id:'3',name:'Erik',lastname:'Richard'}
]
This is what i got so far, if i updated the arrays it duplicates and i need to have only the last updated object
const third = names.map(t1 => ({...t1, ...lastnames.find(t2 => t2.id === t1.id)}))
I'm going to assume since you have the spread operator and Array.find in your example that you can use ES6, which includes for of and Object.values as you see below.
An object and simple looping is used to reduce the amount of times you're iterating. In your example, for every element in names you're iterating over last names to find one with the same ID. Not only is that not ideal for performance, but it doesn't work because every time you're finding the same element with that ID (the first one with that ID in the array).
const names = [
{ id: "1", name: "a", date: "1604616214" },
{ id: "1", name: "Angel", date: "1604616215" },
{ id: "2", name: "b", date: "2004616214" },
{ id: "2", name: "Karen", date: "2004616215" },
{ id: "3", name: "a", date: "3004616220" },
{ id: "3", name: "Erik", date: "3004616221" },
];
const lastnames = [
{ id: "1", lastname: "a", date: "4004616220" },
{ id: "1", lastname: "Ferguson", date: "4004616221" },
{ id: "2", lastname: "b", date: "5004616220" },
{ id: "2", lastname: "Nixon", date: "5004616221" },
{ id: "3", lastname: "a", date: "6004616222" },
{ id: "3", lastname: "Richard", date: "6004616223" },
];
const profiles = {};
function addToProfiles(arr, profiles) {
for (let obj of arr) {
if (obj.id != null) {
// Inits to an empty object if it's not in the profiles objects
const profile = profiles[obj.id] || {};
profiles[obj.id] = { ...profile, ...obj };
}
}
}
addToProfiles(names, profiles);
addToProfiles(lastnames, profiles);
const third = Object.values(profiles);
The idea is to group the objects by their ids, then merge each group according to the rules, maximizing date for each type of record (name and lastname)
// the input data
const names= [
{id:'1',name:'a',date:'1604616214'},
{id:'1',name:'Angel',date:'1604616215'},
{id:'2',name:'b',date:'2004616214'},
{id:'2',name:'Karen',date:'2004616215'},
{id:'3',name:'a',date:'3004616220'},
{id:'3',name:'Erik',date:'3004616221'}
]
const lastnames= [
{id:'1',lastname:'a',date:'4004616220'},
{id:'1',lastname:'Ferguson',date:'4004616221'},
{id:'2',lastname:'b',date:'5004616220'},
{id:'2',lastname:'Nixon',date:'5004616221'},
{id:'3',lastname:'a',date:'6004616222'},
{id:'3',lastname:'Richard',date:'6004616223'}
]
// make one long array
let allNames = [...names, ...lastnames]
// a simple version of lodash _.groupBy, return an object like this:
// { '1': [ { objects with id==1 }, '2': [ ... and so on ] }
function groupById(array) {
return array.reduce((acc, obj) => {
let id = obj.id
acc[id] = acc[id] || [];
acc[id].push(obj);
return acc;
}, {});
}
// this takes an array of objects and merges according to the OP rule
// pick the maximum date name object and maximum date lastname object
// this sorts and searches twice, which is fine for small groups
function mergeGroup(id, group) {
let sorted = group.slice().sort((a, b) => +a.date < +b.date)
let name = sorted.find(a => a.name).name
let lastname = sorted.find(a => a.lastname).lastname
return {
id,
name,
lastname
}
}
// first group, then merge
let grouped = groupById(allNames)
let ids = Object.keys(grouped)
let results = ids.map(id => {
return mergeGroup(id, grouped[id])
})
console.log(results)
I tried to come up with a solution using filter functions. End result contains the format you wanted. check it out.
const names= [
{id:'1',name:'a',date:'1604616214'},
{id:'1',name:'Angel',date:'1604616215'},
{id:'2',name:'b',date:'2004616214'},
{id:'2',name:'Karen',date:'2004616215'},
{id:'3',name:'a',date:'3004616220'},
{id:'3',name:'Erik',date:'3004616221'}
]
const lastnames= [
{id:'1',lastname:'a',date:'4004616220'},
{id:'1',lastname:'Ferguson',date:'4004616221'},
{id:'2',lastname:'b',date:'5004616220'},
{id:'2',lastname:'Nixon',date:'5004616221'},
{id:'3',lastname:'a',date:'6004616222'},
{id:'3',lastname:'Richard',date:'6004616223'}
]
// filter out last updated objects from both arrays
var lastUpdatednames = names.filter(filterLastUpdate,names);
console.log(lastUpdatednames);
var lastUpdatedsurnames = lastnames.filter(filterLastUpdate,lastnames);
console.log(lastUpdatedsurnames);
// combine the properties of objects from both arrays within filter function.
const third = lastUpdatednames.filter(Combine,lastUpdatedsurnames);
console.log(third);
function filterLastUpdate(arrayElement)
{
var max = this.filter( i => arrayElement.id==i.id ).reduce(
function(prev, current)
{
return (prev.date > current.date) ? prev : current
}
)
return max.date == arrayElement.date ;
}
function Combine(firstArray)
{
var subList= this.filter( i => firstArray.id==i.id );
//console.log(subList);
//console.log(subList[0]);
if (subList)
{
firstArray.lastname = subList[0].lastname;
return true;
}
return false ;
}
Here is last output:
[…]
0: {…}
date: "1604616215"
id: "1"
lastname: "Ferguson"
name: "Angel"
1: {…}
date: "2004616215"
id: "2"
lastname: "Nixon"
name: "Karen"
2: {…}
date: "3004616221"
id: "3"
lastname: "Richard"
name: "Erik"

Javascript array restructuring for nested array

I have an array of objects as mentioned below.
const inputArray =[
{
name: "Energy",
quantity: [
{
qval: "100 ",
unit: "unit1"
},
{
qval: "200 ",
unit: "unit2"
}
],
},
{
name: "Fat",
quantity: [
{
qval: "300",
unit: "unit3"
}
],
},
]
I'm trying to restructure this array using the following code and I got something as mentioned below
const outputArray = inputArray.map(function(item,i) {
return {
name: item.name,
amount: (item.quantity[0] &&
item.quantity[0].qval+item.quantity[0].unit)+'|'+ (item.quantity[1] && item.quantity[1].qval+item.quantity[1].unit),
};
});
And here is the output I got
[
{name: "Energy", amount: "100 unit1|200 unit2"}
{name: "Fat", amount: "300unit3|undefined"}
]
Since I'm new to this, I don't think this is a good method, please suggest any simpler neat code.
I'm expecting
[
{name: "Energy", amount: "100 unit1|200 unit2"}
{name: "Fat", amount: "300unit3"}
]
Also I need to remove 'undefined' if that value doesn't exist.
Please suggest.
there you go
inputArray.map(item => ({
name: item.name,
amount: item.quantity.reduce((accumulator, currentValue) => (accumulator+currentValue.qval+currentValue.unit+"|"),"").slice(0, -1)
}))
Here's a pretty simple approach, using a map for the outer list and another one for the quantities for each:
const combine = arr => arr.map(({name, quantity}) => ({
name,
amount: quantity.map(({qval, unit}) => `${qval}${unit}`).join('|')
}))
const inputArray = [{name: "Energy", quantity: [{qval: "100 ", unit: "unit1"}, {qval: "200 ", unit: "unit2"}]}, {name: "Fat", quantity: [{qval: "300", unit: "unit3"}]}]
console.log(combine(inputArray))
The biggest advantage of this approach over yours is that it works for any number of quantities per item. There is no special-case code for the first or second one.
You can add ternary conditions inside your map function to account for variables that might not be declared. For example:
const inputArray =[
{
name: "Energy",
quantity: [
{
qval: "100 ",
unit: "unit1"
},
{
qval: "200 ",
unit: "unit2"
}
],
},
{
name: "Fat",
quantity: [
{
qval: "300",
unit: "unit3"
}
],
},
]
const outputArray = inputArray.map(function(item,i) {
return {
name: item.name,
amount: `${item.quantity[0] ?
item.quantity[0].qval+item.quantity[0].unit : ''}${item.quantity[1] ? `|${item.quantity[1].qval+item.quantity[1].unit}` : ''}`,
};
})
console.log(outputArray);
If the properties of each of the objects isn't guaranteed either- you'd want to add checks for the properties themselves too. For example:
(item[0] && item[0].prop1 && item[0].prop2) ? 'stuff' : 'otherstuff'
You should check for the existance of particular element at index before using it. Here the relevant changes:
const outputArray = inputArray.map(function(item, i) {
var qt = "";
if (item.quantity[0]) {
qt += (item.quantity[0].qval + item.quantity[0].unit);
}
if (item.quantity[1]) {
qt += '|';
qt += (item.quantity[1].qval + item.quantity[1].unit);
}
return {
name: item.name,
amount: qt
};
});
Use a for loop to iterate through the length of item.quantity if there will be an uncertain number of items inside it:
const outputArray = inputArray.map(function(item, i) {
let amountStr = "";
for (i = 0; i < item.quantity.length; i++) {
amountStr += item.quantity[i].qval + item.quantity[i].unit;
// add delimiter when the current item is not the last one in the array
if (i < quantity.length - 1) amountStr += "|";
}
return {
name: item.name,
amount: amountStr
};

Given an array of objects, how do you create a new array of objects with different key names while also omitting unwanted data (ES6 way)?

Sorry for the title, It's limited to 150 characters.
Full code example:
https://jsfiddle.net/c81zw30m/
Data:
Let's say I make an API request and I get this JSON object returned:
[
{
id: 123,
person: {
data: {
name: 'John',
language: 'Javascript'
}
},
details: {
age: 25
},
has_experience: true
},
{
id: 456,
person: {
data: {
name: 'Peter',
language: null // here we have null as a value.
}
},
details: {
age: 40
},
has_experience: false
},
{
id: 789,
person: {
data: {
name: 'Paul',
language: 'Python'
}
},
details: {
age: 30
},
has_experience: null // and here we also don't know if the person is available
},
];
Goal:
The end goal here is to iterate over the array and end up with new array of objects with different key names. Say for example I want to replace the key of person with human or the key of available with availability.
Additionally (optionally) we want to skip adding keys which value is equal to null.
Current solution:
let results = [];
for (let i=0; i< json.length; i++) {
results.push({
user_id: json[i].id,
name: json[i].person.data.name,
age: json[i].details.age,
has_experience: json[i].available ? json[i].available : false // here we are assigning a value no matter what using a ternary operator, what if we want no key:value pair here, just skip that pair
});
if (json[i].person.data.language) { results[i].language = json[i].person.data.language }
}
console.log(results);
Problem:
Now the example and solution I provided works, but imagine if the original API request had hundreds of key:value pairs, and many of them might be of null value.
Question:
Using modern javascript, is there any less verbose and more clean looking/elegant way to handle this problem?
Overall I am looking to create a brand new array of objects based on the original one, but with new key names where necessary. Additionally, we want to skip adding some of them if the value of the key is null for example.
Cheers.
EDIT:
Changed the key name from the example originally provided from available to has_experience because it was a bit misleading. I am not looking to filter out the original array of objects based on the value of a given key. If I wanted to do that I'd start with filter and then chain on.
What I want to do is to omit adding a key:value pair in the newly formed array if the value of the key is null for example.
Using lodash (or similar), you could get your mapping definition out of the mapping loop.
I find the following reasonably concise, though it can probably be shortened a little further.
import { get, set } from "lodash";
let json = [ ... ];
let mapping = new Map([
["user_id", "id"],
["name", "person.data.name"],
["age", "details.age"],
["availability", "available"],
["language", "person.data.language"],
["some.nested.property", "person.data.language"]
]);
var results = json.map(element => {
var mappedElement = {};
mapping.forEach((path, field, map) => {
var value = get(element, path);
if (value) {
set(mappedElement, field, value);
}
});
return mappedElement;
});
console.log(results);
Running this on your data yields
[Object, Object, Object]
0: Object
user_id: 123
name: "John"
age: 25
availability: true
language: "Javascript"
some: Object
nested: Object
property: "Javascript"
1: Object
user_id: 456
name: "Peter"
age: 40
2: Object
user_id: 789
name: "Paul"
age: 30
language: "Python"
some: Object
nested: Object
property: "Python"
Working example: https://codesandbox.io/s/mnkp79668
You can try something like this
You can achieve with map()
let json = [{id: 123, person: { data: { name: 'John', language: 'Javascript' } }, details: { age: 25 }, has_experience: true },
{id: 456, person: { data: { name: 'Peter',language: null } }, details: { age: 40 }, has_experience: false},
{id: 789, person: { data: { name: 'Paul', language: 'Python' } }, details: { age: 30 }, has_experience: null },];
let results = [];
results = json.map(current => {
let temp = {
user_id: current.id,
name: current.person.data.name,
age: current.details.age,
}
if (current.has_experience) {
temp.availablity = current.has_experience
}
if (current.person.data.language)
{ temp.language = current.person.data.language }
return temp;
})
console.log(results);
You have two separate problems to resolve. The first appears to be a requirement for generic flattening of the nested data structures within the input with out specifying every possible key that might exist.
This function will recursively flatten a nested object, along the way omitting any null values. However, this function might overwrite any values where the same key exists at multiple levels, so see below.
function flatten(obj, dest) {
for (let key in obj) {
if (typeof obj[key] === 'object') {
flatten(obj[key], dest);
} else if (obj[key] !== null) {
dest[key] = obj[key];
}
}
return dest;
}
You also want to re-map some of the keys in your data, where the below function can be used both as a pre-processor to convert known duplicate keys into unique keys, and can also be used as a post-processor to convert particular keys back into nested objects. NB: requires "lodash".
function remap(obj, keys) {
for (let [in_key, out_key] of keys) {
let val = _.get(obj, in_key, null);
if (val !== null) {
_.unset(obj, in_key);
_.set(obj, out_key, val);
}
}
return obj;
}
The functions can be chained together like this:
let in_map = new Map([
['user.id', 'user_id']
]);
let out_map = new Map([
['available', 'test.availability']
]);
let out = data.map(obj => remap(obj, in_map))
.map(obj => flatten(obj, {}))
.map(obj => remap(obj, out_map));
I think what you want is to first filter the list, then map over the filtered results to create the new structure. This may not be especially performant however if the list is quite large.
const list = [
{
id: 123,
person: {
data: {
name: 'John',
language: 'Javascript'
}
},
details: {
age: 25
},
available: true
},
{
id: 456,
person: {
data: {
name: 'Peter',
language: null // here we have null as a value.
}
},
details: {
age: 40
},
available: false
},
{
id: 789,
person: {
data: {
name: 'Paul',
language: 'Python'
}
},
details: {
age: 30
},
available: null // and here we also don't know if the person is available
},
];
const newList = list.filter(listItem => listItem.available).map(filteredItem => {
return {
user_id: filteredItem.id,
name: filteredItem.person.data.name,
age: filteredItem.details.age,
availability: !!filteredItem.available
}
})
document.getElementById('list').innerText = JSON.stringify(list, null, 2);
document.getElementById('newList').innerText = JSON.stringify(newList, null, 2);
.container {
display: flex;
}
.container pre {
flex: 0 0 50%;
}
<div class="container">
<pre id="list"></pre>
<pre id="newList"></pre>
</div>

Group multiple elements in array with JavaScript

I have an array
[
{ price: 10 },
{ price: 10 },
{ price: 10 },
{ price: 10 },
{ price: 20 },
{ price: 20 },
]
and I want it transformed into
[
{ numElements: 4, price: 10 },
{ numElements: 2, price: 20 },
]
I have tried using arr.reduce((prev, curr) => ..., []) to accomplish this, but I can't figure out how to do it.
A traditional method might use a for/loop to wrangle the data, but these days JavaScript has a number of functional methods that can help. This code uses reduce and map. To get your data in the format you want is a two stage process.
First, use reduce to create a hash table using the price as a key (because you know the each price is going to be unique:
const obj = arr.reduce((p, c) => {
// If price exists as a key its value by 1
// otherwise set it to 1.
p[c.price] = ++p[c.price] || 1;
return p;
}, {});
OUTPUT
{
"10": 4,
"20": 2
}
As it stands you've got a perfectly good object that you can access by the key/price and I would probably just stop there:
obj['10'] // 4
But if you want to get that data into the format in your question, map over the object keys to return an array of new objects.
const out = Object.keys(obj).map(key => {
return { price: +key, numElements: obj[key] };
});
DEMO
var hash = {}, result = [];
arr.forEach(function(el){
if(hash[el.price]){
hash[el.price].numElements++;
}else{
result.push(hash[el.price]={price:el.price,numElements:1});
}
});
Run
May use a hash table for price lookup. Or with reduce and find:
arr.reduce((res,{price})=>
(( res.find(el=>el.price===price) || res[res.push({price,numElements:0})-1] )
.numElements++,res)
);
Run
You can use try this:
let arr = [
{ price: 10 },
{ price: 10 },
{ price: 10 },
{ price: 10 },
{ price: 20 },
{ price: 20 },
]
let result = []
let counter = {}
arr.forEach( el => {
if (!counter[el.price]) counter[el.price] = 1
else counter[el.price]++
console.log(counter[el.price])
})
for (let id in counter) {
result.push({numElements: counter[id], price: id})
}
Assuming that the data comes sorted on price property, with a single .reduce() you may do as follows;
var data = [{ price: 10 }, { price: 10 }, { price: 10 }, { price: 10 }, { price: 20 }, { price: 20 }],
result = data.reduce((r,d,i) => i ? r[r.length-1].price === d.price ? (r[r.length-1].numElemenets++, r)
: (r.push(Object.assign({}, d, {numElemenets: 1})),r)
: [Object.assign({}, d, {numElemenets: 1})], {});
console.log(result);
You could look up the price in the result array and if not found insert a new object.
var data = [{ price: 10 }, { price: 10 }, { price: 10 }, { price: 10 }, { price: 20 }, { price: 20 }],
grouped = data.reduce((r, { price }) => {
var t = r.find(p => price === p.price);
t || r.push(t = { numElements: 0, price });
t.numElements++;
return r;
}, []);
console.log(grouped);

Categories