Count object property inside array using lodash or vanilla javascript - javascript

I have this object with nested arrays/objects:
{
"USA": [
{
"location": "New York",
"municipality": "Manhattan",
},
{
"location": "Texas",
"municipality": "Austin",
}
],
"CANADA": [
{
"location": "Ontario",
"municipality": "no municipality",
}
]
}
I want to use lodash or plain javascript to count how many location are inside the USA and CANADA. How is that possible?
desired result:
USA: 2
CANADA: 1

Just use the array lengths:
var USA = myObj.USA.length;
var Canada = myObj.CANADA.length;
Or, for larger data sets:
var result = {};
Object.keys(myObj)
.forEach(function(key,index) {
result[key] = myObj[key].length;
});

With lodash you could use mapValues:
let result = _.mapValues(data, 'length');

The solution using Array.prototype.reduce() function:
var obj = {
"USA": [ { "location": "New York", "municipality": "Manhattan" }, { "location": "Texas", "municipality": "Austin" } ], "CANADA": [ { "location": "Ontario", "municipality": "no municipality" }]
},
result = Object.keys(obj).reduce(function(r,k){
r[k] = obj[k].length;
return r;
}, {});
console.log(result)

Related

create new city state object

I would like to transform my initial data to desired result, I am struggling with pushing the cities to the array and making sure name key is unique.
initial data
[
{ "city": "Abbeville", "state": "Louisiana" },
{ "city": "Aberdeen", "state": "Maryland" },
{ "city": "Aberdeen", "state": "Mississippi" },
{ "city": "Aberdeen", "state": "South Dakota" },
{ "city": "Aberdeen", "state": "Washington" },
{ "city": "Abilene", "state": "Texas" },
{ "city": "Abilene", "state": "Kansas" },
{ "city": "Abingdon", "state": "Virginia" },
{ "city": "Abington", "state": "Massachusetts" },
{ "city": "Abington", "state": "Massachusetts" },
]
code
let newCityStateObject = cities.map((item, index) => {
console.log("item ", item);
if (item) {
let object = {};
let citiesArray = [];
//set state and create empty array
if (object[item.state] === undefined) {
object.name = item.state;
object.cities = [].push(item.city);
} else {
//key exists so just push to array
if (object[item.state]) {
object.cities.push(item.city);
}
}
console.log("end ", object);
return object;
}
});
my result right now
[
{ state: 'Louisiana', cities: [] },
{ state: 'Maryland', cities: [] },
{ state: 'Mississippi', cities: [] },
{ state: 'South Dakota', cities: [] },
{ state: 'Washington', cities: [] },
{ state: 'Texas', cities: [] },
{ state: 'Kansas', cities: [] },
{ state: 'Virginia', cities: [] },
]
desired result
[
{
"name": "Kentucky",
"cities": [
"Louisville/Jefferson County",
"Lexington-Fayette",
"Bowling Green",
"Owensboro",
"Covington"
]
},
{
"name": "Maryland",
"cities": [
"Baltimore",
"Frederick",
"Rockville",
"Gaithersburg",
"Bowie",
"Hagerstown",
"Annapolis"
]
}
]
Any help/tips or pointing in the right direction to solve this would be greatly appreciated.
You’re basically grouping cities by their state. First of all, array.map is not the proper method for this problem, cus when you group, the input item’s number might not match with the output’s. array.reduce is better option.
let newCityStateObject = cities.reduce((acc, item, index) => {
if (item) {
// this object has state as key, and the desired output array’s item as value
const object = acc.obj;
// if state not found, create new record
if (object[item.state] === undefined) {
const record = { name: item.state, cities: [] }
object[item.state] = record;
acc.array.push(record);
}
const record = object[item.state];
record.cities.push(item.city);
}
return acc;
}, { obj: {}, array: [] }).array;
I like the answer suggested by #hackape.
Here is one more way to consider:
let newCityStateObject = () => {
const statesArr = Array.from(cities, (item) => item.state);
// Remove state duplications
const filteredStates = [...new Set(statesArr)];
// Initializing the name and cities object and array
let result = filteredStates.map((item) => {
return { name: item, cities: [] };
});
// For each cite item, fetch the city to its corresponding result by state
cities.forEach((item) =>
result
.find((element) => element.name === item.state)
.cities.push(item.city)
);
return result;
}

Pivot or Transforming JavaScript object

I have the following JavaScript object. I need to generate a new object from the given object. What is the approach I should take in JavaScript?
[
{"name": "Dan", "city" : "Columbus", "ZIP":"47201"},
{"name": "Jen", "city" : "Columbus", "ZIP":"47201"},
{"name": "Mark", "city" : "Tampa", "ZIP":"33602"},
]
How can I transform or pivot to generate the following object?
[
{ "47201": [
{"name": "Dan", "city": "Columbus"},
{"name": "Jen", "city": "Columbus"},
],
"count": "2"
},
{ "33602": [
{"name": "Mark", "city": "Tampa"}
],
"count": "1"
}
]
I don't know why you want the .count property, when that can be accessed via the array's .length property, but anyway:
const input = [
{"name": "Dan", "city" : "Columbus", "ZIP":"47201"},
{"name": "Jen", "city" : "Columbus", "ZIP":"47201"},
{"name": "Mark", "city" : "Tampa", "ZIP":"33602"},
]
const working = input.reduce((acc, {ZIP, name, city}) => {
(acc[ZIP] || (acc[ZIP] = [])).push({name, city})
return acc
}, {})
const output = Object.keys(working)
.map(k => ({[k]: working[k], count: working[k].length}))
console.log(output)
Further reading:
Array .reduce()
Array .map()
Object.keys()
Unpacking fields from objects passed as function parameters
Computed property names
The below code will work for your requirement. The final result is stored in the variable result which holds the array object.
var source = [{
"name": "Dan",
"city": "Columbus",
"ZIP": "47201"
},
{
"name": "Mark",
"city": "Tampa",
"ZIP": "33602"
},
{
"name": "Jen",
"city": "Columbus",
"ZIP": "47201"
}
];
var result = [];
finalarr('ZIP');
function finalarr(propname) {
var obj = JSON.parse(JSON.stringify(source));
obj.forEach(function(elm,i) {
var arr = {};var chli=[];var charr={};
var flag = 0;
for (var prop in elm) {
if(prop != propname){
charr[prop]=elm[prop];
}
}
for(var i=0;i<result.length;i++){
if(result[i][elm[propname]]){
result[0][elm[propname]].push(charr);
//console.log(result[i][propname]);
flag = 1;
}
}
if(flag == 0){
chli.push(charr);
arr["count"] = checkarr(obj,propname,elm[propname]);
arr[elm[propname]]=chli;
result.push(arr);
}
});
}
function checkarr(obj,propname,value){
var count = 0;
obj.forEach(function(elm,i) {
if(elm[propname] == value){
count++;
}
});
return count;
}
console.log(result);

Organise element in a array

i'm searching a smart way to reoganise an array by a element inside it:
In entry i've got:
[{"name": "brevet",
"country": "fr"
},{
"name": "bac",
"country": "fr"
},{
"name": "des",
"country": "ca"
},{
"name": "dep",
"country": "ca"
}{
"name": "other",,
"country": "other"}]
I want to reorganize my array by country to have this in my output:
[{
"name": "fr",
"degrees": [
{
"name": "brevet",
"country": "fr"
},{
"name": "bac",
"country": "fr"
}]
},{
"name": "ca",
"degrees": [{
"name": "des",
"country": "ca"
},{
"name": "dep",
"country": "ca"
}]
},{
"name": "other",
"degrees": [{
"name": "other",
"country": "other"
}]
}]
For this i write a dirty function, but it seems to me there is a better way but i don't see how. If someone can ligth my brain in a better way to do this i'll be helpfull
private organizeDegrees(degrees: Array<SubscriptionFieldInterface>) {
let degreesByCountry = new Array();
let storeIndex = new Array();
degrees.map(degree => {
let index = null;
storeIndex.find((element, idx) => {
if (element === degree.country) {
index = idx;
return true;
}
});
if (index === null) {
index = degreesByCountry.length;
let newEntry = {
'name': degree.country,
'degrees': new Array()
};
storeIndex.push(degree.country);
degreesByCountry.push(newEntry);
}
degreesByCountry[index].degrees.push(degree);
});
return degreesByCountry;
}
thank's
You can group the array and map the object using Object.keys:
var groupBy = function(xs, key) {
return xs.reduce(function(rv, x) {
(rv[x[key]] = rv[x[key]] || []).push(x);
return rv;
}, {});
};
var grouped = groupBy(array, "country");
var mappedArray = Object.keys(grouped).map(key => ( {name: key, degrees: grouped [key]} ));
And one more way:
arr = [ /* your array */ ];
arr = Object.values(arr.reduce((ac, el) => {
if(!ac[el.country]) ac[el.country] = {"name": el.country, "degrees": []}
ac[el.country].degrees.push(el);
return ac
}, {}))
console.log(arr) // formated
Another solution, which also handles 'id' => '#id' mapping:
const a = [{"name":"brevet","country":"fr"},{"name":"bac","country":"fr"},{"id":73,"name":"des","country":"ca"},{"name":"dep","country":"ca"},{"name":"other","country":"other"}];
const r = [...new Set(a.map(({country}) => country))] // list of unique country names
.map(c => Object.assign({name: c}, // for each country
{degrees: a.filter(x => x.country === c).map(y => Object.keys(y).includes('id') // handle 'id' => '#id' mutation
? {'#id': "/subscription_fields/" + y.id, name: y.name, country: y.country}
: y)
}))
console.log(r)
This is purely ES6, and quite terse, but possibly less readable. Also, it doesn't add the "#id": "/subscription_fields/83", which could be added as a post process:
const groupByKey = (arr, key) => [...arr.reduce((acc, deg) =>
acc.set(deg[key], {name: deg[key], degrees: [ ...(acc.get(deg[key]) || {degrees: []}).degrees, deg]})
, new Map()).values()];
console.log(groupByKey(degrees, 'country'));
You could use a hash table and collect all values in an object. For getting the result array, you need to push the object only once.
var data = [{ name: "brevet", country: "fr" }, { name: "bac", country: "fr" }, { id: 73, name: "des", country: "ca" }, { name: "dep", country: "ca" }, { name: "other", country: "other" }],
result = data.reduce(function (hash) {
return function (r, a) {
if (!hash[a.country]) {
hash[a.country] = { name: a.country, degrees: [] };
r.push(hash[a.country]);
}
hash[a.country].degrees.push({ name: a.name, country: a.country });
return r;
};
}(Object.create(null)), []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

how to reorganize an array of object using lodash

Is there a way I can make A to B using lodash? Appreciated.
A - Original array looks like below.
[
{
"customerId": 5458122321,
"customerName": "C1"
},
{
"customerId": 5461321801,
"customerName": "C1"
},
{
"customerId": 5434315807,
"customerName": "C2"
}
]
B - and I want it to be something like below.
[
{
"customerId": [5461321801, 5458122321]
"customerName": "C1"
},
{
"customerId": [5434315807],
"customerName": "C2"
}
]
Pure JS solution using Array.prototype.reduce() and Object.keys() functions:
var A = [
{ "customerId": 5458122321, "customerName": "C1" }, { "customerId": 5461321801, "customerName": "C1" }, { "customerId": 5434315807, "customerName": "C2" }
],
// accumulating an object "indexed" by 'customerName' attributes
// for grouping 'customers' by same name
B = A.reduce(function (r, o) {
(r[o.customerName])?
r[o.customerName]["customerId"].push(o.customerId)
: r[o.customerName] = {customerId: [o.customerId], customerName: o.customerName};
return r;
}, {}),
// getting values from the object 'B'
result = Object.keys(B).map(function(k){ return B[k]; });
console.log(result);
Here's a lodash solution that makes use of groupBy to group the collection by their customerName, map to transform each grouped items and then use map again to get all customerId in a grouped collection.
var result = _(source)
.groupBy('customerName')
.map(function(group, name) {
return {
customerId: _.map(group, 'customerId'),
customerName: name
};
}).value();
var source = [
{
"customerId": 5458122321,
"customerName": "C1"
},
{
"customerId": 5461321801,
"customerName": "C1"
},
{
"customerId": 5434315807,
"customerName": "C2"
}
];
var result = _(source)
.groupBy('customerName')
.map(function(group, name) {
return {
customerId: _.map(group, 'customerId'),
customerName: name
};
}).value();
console.log(result);
body > div { min-height: 100%; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>
solution with _.reduce
var B = _.reduce(A, function(result, item) {
var addedItem = _.find(result, {customerName: item.customerName});
if (addedItem) {
addedItem.customerId.push(item.customerId);
return result;
}
item.customerId = [item.customerId];
return _.concat(result, item);
}, []);

sorting json data in javascript

Below is the json data that I have which contains array of states. The size of array is always 2, but the order of elements of the array is not fixed. The array elements values can be null. The sample data is as shown below:
{
"status": "SUCCESS",
"status_message": "Susscessfully queried details.",
"total_records": 2,
"m_details":
[
{
"p_id": 1023,
"pname": "india",
"states":
[
{
"state": "karnataka",
"capital": "bangalore"
},
{
"state": null,
"capital": null,
}
]
},
{
"p_id": 1023,
"pname": "india",
"states":
[
{
"state": null,
"capital": null
},
{
"state": "Tamilnadu",
"capital": "chennai"
}
]
}
]
}
My questions:
How to convert the null values to some default text say "-".
How can I sort all the states in asc or desc order.
You can iterate through all elements in your data to switch any null values to "-" with an iterator with a callback like this.
function iterateObject(item, callback) {
if (typeof item === "object" && item !== null) {
if (item instanceof Array) {
for (var i = 0; i < item.length; i++) {
item[i] = iterateObject(item[i], callback);
}
} else {
for (var prop in item) {
if (item.hasOwnProperty(prop)) {
item[prop] = iterateObject(item[prop], callback);
}
}
}
} else {
// call the callback on any item that is not an array or object
return callback(item);
}
return item;
}
var data = {
"status": "SUCCESS",
"status_message": "Susscessfully queried details.",
"total_records": 2,
"m_details":
[
{
"p_id": 1023,
"pname": "india",
"states":
[
{
"state": "karnataka",
"capital": "bangalore"
},
{
"state": null,
"capital": null,
}
]
},
{
"p_id": 1023,
"pname": "india",
"states":
[
{
"state": null,
"capital": null
},
{
"state": "Tamilnadu",
"capital": "chennai"
}
]
}
]
};
// iterate through the object and convert all `null` values to `"-"`
iterateObject(data, function(item) {
return (item === null) ? "-" : item;
});
You can then sort each of the states arrays like this:
function sortStates(item) {
var array = item.m_details;
for (var i = 0; i < array.length; i++) {
array[i].states.sort(function(a, b) {
return a.state.localeCompare(b.state);
});
}
}
sortStates(data);
If you want the opposite sort order, then just swap the arguments a and b in the .sort() callback.
Working demo: http://jsfiddle.net/jfriend00/MTQ86/
Just for your information javascript array objects have a sort function that implements some basic built in sorting functionalities. If you need to perform a more specific sorting (you do) you can always passing in a function to the sort function and implement your own custom logic. This article from W3Schools has some examples which quoting one of them here...
var points = [40,100,1,5,25,10];
points.sort(function(a,b){return b-a}); //sorts numbers in descending order
Now, to "convert" null values to a '-' literal I guess you will need to add more details to your question so I can provide a good solution. Why do you need to convert them? Where's this json coming from?

Categories

Resources