This question already has answers here:
Javascript group a JSON object by two properties and count
(7 answers)
Group and count values in an array
(4 answers)
Closed 1 year ago.
Given a sample JSON array of objects, like this....
[
{
"firstName": "Bob",
"lastName": "Smith",
"city": "Preston",
"st": "Florida",
"age": 15
},
{
"firstName": "Tom",
"lastName": "Jones",
"city": "Springfield",
"st": "Illinois",
"age": 34
},
{
"firstName": "Mary",
"lastName": "Hart",
"city": "Miami",
"st": "Florida",
"age": 22
},
{
"firstName": "Jenny",
"lastName": "Dixon",
"city": "Palm City",
"st": "Florida",
"age": 26
}
]
What is the best way to get the number of occurrences based on the groupings of a particular property? So, let's say I want to produce a JSON object that has each unique state ("st") and the number of occurrences....
[
{
"st": "Illinois",
"count": 1
},
{
"st": "Florida",
"count": 3
}
]
I can do it manually using a for-let, looping through the array, tracking the values as I loop, etc. But I'm sure there's a more efficient way using ES6. Can you please help me out? Thanks.
You can use Array#reduce to keep a tally
let counts = json.reduce((b, a) => {
let index = b.findIndex(j => j.st === a.st);
if (index > -1) b[index].count++;
else b.push({st: a.st, count: 1});
return b;
}, [])
#UPDATE: As mentioned by #epascarello, there is a more efficient way to go about this, removing the findIndex loop and using Object.values
const results = Object.values(json.reduce((obj, item) => {
obj[item.st] = obj[item.st] || { st: item.st, count: 0 };
obj[item.st].count++;
return obj;}, {}))
let json = [{
"firstName": "Bob",
"lastName": "Smith",
"city": "Preston",
"st": "Florida",
"age": 15
},
{
"firstName": "Tom",
"lastName": "Jones",
"city": "Springfield",
"st": "Illinois",
"age": 34
},
{
"firstName": "Mary",
"lastName": "Hart",
"city": "Miami",
"st": "Florida",
"age": 22
},
{
"firstName": "Jenny",
"lastName": "Dixon",
"city": "Palm City",
"st": "Florida",
"age": 26
}
]
let counts = json.reduce((b, a) => {
let index = b.findIndex(j => j.st === a.st);
if (index > -1) b[index].count++;
else b.push({st: a.st, count: 1});
return b;
}, [])
console.log(counts)
const results = Object.values(json.reduce((obj, item) => {
obj[item.st] = obj[item.st] || { st: item.st, count: 0 };
obj[item.st].count++;
return obj;}, {}))
console.log(results)
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
I have the following data structure:
const data = {
"firstName": "A",
"lastName": "B",
"address": [{
"country": "France",
"city": "Paris"
},
{
"country": "Italy",
"city": "Rome"
}
],
};
Using Ramda I would like to transforms it into:
const result = [
{
"firstName": "A",
"lastName": "B",
"address": {
"country": "France",
"city": "Paris"
},
},
{
"firstName": "A",
"lastName": "B",
"address": {
"country": "Italy",
"city": "Rome"
},
},
];
You can use a converge function to fork the prop address and then join it with the main object for each address in the list:
/**
* R.pick could be replaced with R.omit
* to let you black list properties:
* R.omit(['address']); https://ramdajs.com/docs/#omit
**/
const createByAddress = R.converge(R.map, [
R.pipe(R.pick(['firstName', 'lastName']), R.flip(R.assoc('address'))),
R.prop('address'),
]);
const data = {
"firstName": "A",
"lastName": "B",
"address": [{
"country": "France",
"city": "Paris"
},
{
"country": "Italy",
"city": "Rome"
}
],
};
console.log(createByAddress(data));
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js" integrity="sha256-xB25ljGZ7K2VXnq087unEnoVhvTosWWtqXB4tAtZmHU=" crossorigin="anonymous"></script>
My question is why "with Ramda"? I'm a founder of Ramda and a big fan, but it's just a tool, and unless this is a learning exercise for Ramda, it doesn't seem like there is any need to use it for this problem.
I would do it like this, using modern JS techniques:
const transform = ({address, ...rest}) =>
address .map (a => ({...rest, address: a}))
const data = {firstName: "A", lastName: "B", address: [{country: "France", city: "Paris"}, {country: "Italy", city: "Rome"}]}
console .log (
transform (data)
)
I am not sure if this will help you but if you want to generate multiple objects based on adress maybe this helps
const obj = {
firstName: "a",
lastName: "b",
adresses: [{
country: "France",
city: "Paris"
}, {
country: "Italy",
city: "Rome"
}]
};
adressAmount = obj.adresses.length;
const adressObjects = [];
for (let i = 0; i < adressAmount; i++) {
const {
adresses,
...objWithoutAdresses
} = obj;
objWithoutAdresses.adress = obj.adresses[i];
adressObjects.push(objWithoutAdresses);
}
console.log(adressObjects);
I found this pretty simple and short.
const data = {
"firstName": "A",
"lastName": "B",
"address": [{
"country": "France",
"city": "Paris"
},
{
"country": "Italy",
"city": "Rome"
}
],
};
let requiredData = data.address.map(element=>{
return {...data,address:element}
})
console.log(requiredData);
1) Create an empty dictionary
2) for loop the array and store index of each array in the dictionary as value
You can iterate the address array and create object as required
let obj = {
"firstName": "A",
"lastName": "B",
"address": [{
"country": "France",
"city": "Paris"
},
{
"country": "Italy",
"city": "Rome"
}
]
}
let newData = obj.address.map(function(item) {
return {
firstName: obj.firstName,
lastName: obj.lastName,
address: {
country: item.country,
city: item.city
}
}
});
console.log(newData)
I search how to sort by place.city this kind of object who have id's for keys. The need is to keep id's for first keys…
{
"123": {
"place": {
"city": "New York",
"country": "USA"
},
"person": {
"name": "Bob",
"age": 45
}
},
"456": {
"place": {
"city": "Chicago",
"country": "USA"
},
"person": {
"name": "Louis",
"age": 34
}
},
"789": {
"place": {
"city": "Dallas",
"country": "USA"
},
"person": {
"name": "Kevin",
"age": 27
}
}
}
I try some kind of function like this and the expected result is not here.
let result = _(myObject).map(function (value, key) {
return _.defaults({ name: key }, value)
}).sortBy('city').value()
You can't sort an object.. You can, however, convert your object to an array and sort that.
var data ={
"123" : {
"place": {
"city": "New York",
"country": "USA"
},
"person": {
"name": "Bob",
"age": 45
}
},
"456" : {
"place": {
"city": "Chicago",
"country": "USA"
},
"person": {
"name": "Louis",
"age": 34
}
},
"789" : {
"place": {
"city": "Dallas",
"country": "USA"
},
"person": {
"name": "Kevin",
"age": 27
}
}
};
var sortedByPlace = _.sortBy(Object.keys(data).map(k => ({id:k, ...data[k]})), (d)=> d.place.city)
console.log(sortedByPlace);
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.5/lodash.min.js"></script>
It is not possible to sort an object, you need to make it a list.
import { map, flow } from 'lodash'
import { sortBy } from 'lodash/fp'
cities => flow(
map(places, (place, id) => { id, ...place }),
sortBy('city'),
)()
Your second question begs the question (mh...) if you want local sort. That would be
import { mapValues } from 'lodash'
import { sortBy } from 'lodash/fp'
data => mapValues(data, sortBy('place.city'))
You cant sort an object. However you could create a sorted array that contains references to the objects:
const sorted = Object.values(myObject).sort((a, b) => a.place.city.localeCompare(b.place.city));
If you look at this answer, the following should work
var sort = function (prop, arr) {
prop = prop.split('.');
var len = prop.length;
arr.sort(function (a, b) {
var i = 0;
while( i < len ) { a = a[prop[i]]; b = b[prop[i]]; i++; }
if (a < b) {
return -1;
} else if (a > b) {
return 1;
} else {
return 0;
}
});
return arr;
};
sort("place.city", myObject);
I realize the object I have to treat (get from an obscur API) is a little bit more complicated than my first example :/
So the responses you nicely give are not working anymore…
Do you see the subtlety on this new object ?
The point stay to sort by place.city
{
"123": {
0: {
"place": {
"city": "New York",
"country": "USA"
},
"person": {
"name": "Bob",
"age": 45
}
},
1: {
"place": {
"city": "New York",
"country": "USA"
},
"person": {
"name": "James",
"age": 32
}
}
},
"456": {
0: {
"place": {
"city": "Chicago",
"country": "USA"
},
"person": {
"name": "Louis",
"age": 34
}
},
1: {
"place": {
"city": "Chicago",
"country": "USA"
},
"person": {
"name": "Christine",
"age": 65
}
}
},
"789": {
0: {
"place": {
"city": "Dallas",
"country": "USA"
},
"person": {
"name": "Kevin",
"age": 27
}
},
1: {
"place": {
"city": "Dallas",
"country": "USA"
},
"person": {
"name": "Robert",
"age": 55
}
},
2: {
"place": {
"city": "Dallas",
"country": "USA"
},
"person": {
"name": "Danny",
"age": 62
}
}
}
}
Let's say I have two deep objects:
var oldData = {
"id": 1,
"first_name": "Eric",
"last_name": "Henry",
"info": {
"email": "ehenry0#smh.com.au",
"gender": "Male",
"ip_address": "7.11.169.150",
"age": 11
}
};
var newData = {
"id": 2,
"first_name": "Tommy",
"last_name": "Henry",
"info": {
"email": "tommy#ghenrry.com",
"gender": "Male",
"ip_address": "7.11.169.150",
"age": 15
}
};
How would I use lodash (or JavaScript) to traverse through each object and get the value of each different value, so in the top case it would be
[
{old: 1, new: 2},
{old: 'Eric', new: 'Tommy'},
{old: 'ehenry0#smh.com.au', new: 'tommy#ghenrry.com'},
{old: 11, new: 15},
]
Here is what I have so far:
var oldData = {
"id": 1,
"first_name": "Eric",
"last_name": "Henry",
"info": {
"email": "ehenry0#smh.com.au",
"gender": "Male",
"ip_address": "7.11.169.150",
"age": 11
}
};
var newData = {
"id": 2,
"first_name": "Tommy",
"last_name": "Henry",
"info": {
"email": "tommy#ghenrry.com",
"gender": "Male",
"ip_address": "7.11.169.150",
"age": 15
}
};
var diffObj = _.difference(_.keys(oldData), _.keys(newData));
console.log(JSON.stringify(diffObj, null, 4));
<script src="https://cdn.jsdelivr.net/lodash/4.17.4/lodash.min.js"></script>
The solution using custom recursive function compareUserData and Object.keys() function:
var oldData = { "id": 1, "first_name": "Eric", "last_name": "Henry", "info": { "email": "ehenry0#smh.com.au", "gender": "Male", "ip_address": "7.11.169.150", "age": 11 }
};
var newData = { "id": 2, "first_name": "Tommy", "last_name": "Henry", "info": { "email": "tommy#ghenrry.com", "gender": "Male", "ip_address": "7.11.169.150", "age": 15 }
};
function compareUserData(oldData, newData, result) {
Object.keys(oldData).forEach(function (k) {
if (typeof oldData[k] !== 'object') {
if (oldData[k] != newData[k]) this.push({'old': oldData[k], 'new': newData[k]});
} else {
compareUserData(oldData[k], newData[k], this);
}
}, result);
return result;
}
var result = compareUserData(oldData, newData, []);
console.log(result);
You may want to iterate through your objects properties, and check manually if something changed.
To see how you can iterate on properties : Iterate through object properties
EDIT : Your object has nested properties, read this post to see how you can check that too : How do I check if an object has a property in JavaScript?
This question already has answers here:
Sorting Object by sub-object property
(4 answers)
Closed 7 years ago.
How to sort the objects by age value?
I have the following object structure
{
"men": {
"20114": {
"id": "20114",
"name": "Peter",
"age": "21"
},
"28957": {
"id": "28957",
"name": "Paul",
"age": "20"
}
},
"women": {
"8957": {
"id": "8957",
"name": "Rose",
"age": "24"
},
"2178": {
"id": "2178",
"name": "Sara",
"age": "22"
}
},
}
I know, that I can sort arrays like this
groups.sort(function(a, b) {
return b.age - a.age;
});
but how to do this with objects?
It would be a lot easier to sort your data if you could change your structure to the JSON model below:
var data = [
{
"id": "20114",
"name": "Peter",
"age": "21",
"gender": "men"
},
{
"id": "28957",
"name": "Paul",
"age": "20",
"gender": "men"
},
{
"id": "8957",
"name": "Rose",
"age": "24",
"gender": "women"
},
{
"id": "2178",
"name": "Sara",
"age": "22",
"gender": "women"
}
]
data.sort(function(a, b) {
return parseFloat(a.age) - parseFloat(b.age);
});
data.sort()
document.write(JSON.stringify(data))
function sortfunc(prop){
return function(obj1,obj2){
var val1 = obj1[prop];
var val2 = obj2[prop];
return val1 - val2;
};
}
groups.sort(sortfunc(prop));
pass prop as property name
I have an array in the below format which I need to filter based on the key and value. I am planning to use Underscore.js for this. I tried using the following code but it searches for all the fields value but I need to search based on the key and value and not in all the keys. How to use Underscore for this?
Please let me know.
var sortedArray = _.sortBy(_.filter(arr, function (obj) {
return _.values(obj).some(function (el) {
return (typeof el ==="string" && el.match(new RegExp(searchStr, "i")));
});
}), function (obj){
return obj[colName];
});
}
{
"recordsTotal": 5,
"recordsFiltered": 5,
"aaData": [
{
"firstname": "Pradeep",
"lastname": "Kumar",
"city": "Bangalore",
"country": "India"
},
{
"firstname": "John",
"lastname": "Wells",
"city": "Calcutta",
"country": "India"
},
{
"firstname": "Praveen",
"lastname": "Garg",
"city": "columbo",
"country": "Srilanka"
},
{
"firstname": "Joe",
"lastname": "Wells",
"city": "Luton",
"country": "UK"
},
{
"firstname": "Rita",
"lastname": "Wahlin",
"city": "houston",
"country": "USA"
}
]
}
Sorry if I was not able to post the question properly. I found a solution and the is using the below code.
var searchColData=function(arr, searchStr, colName){
var sortedArray = _.filter(arr, function (obj) {
return (_.property(colName)(obj).toString().match(new RegExp(searchStr, "i")));
});
return sortedArray;
}
Hope this helps someone.