Trying to iterate between 2 var obj and merge them - javascript

I have:
const dictionary = [
{
"state": "AK",
"lat": "9875.33.00",
"long": "-8371.42.00",
"name": "Alaska"
},
{
"state": "AL",
"lat": "5335.51.00",
"long": "-15124.18.00",
"name": "Alabama"
}
];
const data = [
{
"date": 20200421,
"state": "AK",
},
{
"date": 20200421,
"state": "AL",
}
];
const result = data.map(item => ({...item, lat: dictionary[item.state].lat, long: dictionary[item.state].long }))
console.log(result);
Basically trying to add dictionary as objs per each data where the state matches but I'm having:
Cannot read property 'lat' of undefined
Expecting:
const result = [
{
"date": 20200421,
"state": "AK",
"lat": "9875.33.00",
"long": "-8371.42.00",
},
{
"date": 20200421,
"state": "AL",
"lat": "5335.51.00",
"long": "-15124.18.00",
}
];
I'm trying on fiddle

You cannot access the array items as one whole array. You have to isolate you desired obj. Use this.
const result = data.map(function(item) {
const ditem = dictionary.find(d => d.state == item.state);
if(ditem) {
return {
...item,
"lat": ditem.lat ,
"long": ditem.long
}
}
return item;
});
console.log(result);

You could take an object with state as key and merge new objects by taking name out of the object.
const
dictionary = [{ state: "AK", lat: "9875.33.00", long: "-8371.42.00", name: "Alaska" }, { state: "AL", lat: "5335.51.00", long: "-15124.18.00", name: "Alabama" }],
data = [{ date: 20200421, state: "AK" }, { date: 20200421, state: "AL" }],
states = data.reduce((r, o) => (r[o.state] = o, r), {}),
merged = dictionary.map(({ name, ...o }) => ({ ...(states[o.state] || {}), ...o }));
console.log(merged);
.as-console-wrapper { max-height: 100% !important; top: 0; }

const dictionary = [
{
"state": "AK",
"lat": "9875.33.00",
"long": "-8371.42.00",
"name": "Alaska"
},
{
"state": "AL",
"lat": "5335.51.00",
"long": "-15124.18.00",
"name": "Alabama"
}
];
const data = [
{
"date": 20200421,
"state": "AK",
},
{
"date": 20200421,
"state": "AL",
}
];
let result = dictionary.filter(element =>{
for(let i = 0; i < data.length; i++){
if(data[i].state == element.state) return element;
}
})
console.log(result);

Related

How to group array obj by?

I'm new to grouping array obj. I tried the following and I believe I'm getting there but I'm missing something and I don't understand where:
Doing:
const result = data.map(function(item) {
const ditem = dictionary.find(d => d.state == item.state);
if(ditem) {
return {
...item,
"lat": ditem.lat ,
"long": ditem.long
}
}
return item;
});
console.log(result);
const formatted = result.map(area => {
return {
"state": area["state"],
"lat": area["lat"],
"long": area["long"],
"datasets": Object.keys(area)
.map(date => ({ date: area[date], negative: area[date]}))
};
});
Giving me:
[
{
"state": "AK",
"lat": "9875.33.00",
"long": "-8371.42.00",
"datasets": [
{
"date": 20200421,
"negative": 20200421
},
{
"date": "AK",
"negative": "AK"
},
{
"date": 329,
"negative": 329
},
{
"date": 10790,
"negative": 10790...
Expecting example:
0:
State: "AK",
Lat: 45.0732745
Long: 7.680687483
0: date: "2/24/20"
positive: 329
negative: 10790
pending: null
hospitalizedCurrently: 42
hospitalizedCumulative: 36...
1:
date: "2/25/20",
positive: 329
negative: 10790
pending: null
hospitalizedCurrently: 42
hospitalizedCumulative: 36...
This might be the code you are looking for:
const formatted = Object.assign({},result.map(area => {
return {
"state": area["state"],
"lat": area["lat"],
"long": area["long"],
"datasets": Object.assign({},Object.keys(area)
.map(date => ({ date: area[date], negative: area[date]})))
};
}))

Transforming a JSON structure in javascript

I have data for a simple online store coming from a headless CMS. The data looks like this:
[
{
"id": 12312,
"storeName": "Store1",
"googleMapsUrl": "https://example1.com",
"country": "Australia",
"state": "New South Wales"
},
{
"id": 12313,
"storeName": "Store2",
"googleMapsUrl": "https://example2.com",
"country": "Australia",
"state": "Queensland"
},
{
"id": 12314,
"storeName": "Store3",
"googleMapsUrl": "https://example3.com",
"country": "Indonesia",
"state": "Java"
},
]
This data will be used to make a simple store locator sorted by 1) Country and 2) State.
I'm unable to change anything on the CMS. Looking for suggested way to loop through this flat data object and list by country and state.
EDIT: I created this to extract the unique countries:
let newArray = this.$page.stores.edges.map(item =>{
let newObj = {};
newObj[item.node.country] = item.node.country;
newObj[item.node.country.state] = item.node.state;
console.log(newObj)
return newObj;
});
But again from there not sure how I would connect that to states and ultimately stores.
Ordered by country and state.
var data = [{
"id": 12314,
"storeName": "Store3",
"googleMapsUrl": "https://example3.com",
"country": "Indonesia",
"state": "Java"
},
{
"id": 12315,
"storeName": "Store4",
"googleMapsUrl": "https://example4.com",
"country": "Australia",
"state": "Queensland"
},
{
"id": 12312,
"storeName": "Store1",
"googleMapsUrl": "https://example1.com",
"country": "Australia",
"state": "New South Wales"
},
{
"id": 12313,
"storeName": "Store2",
"googleMapsUrl": "https://example2.com",
"country": "Australia",
"state": "Queensland"
},
]
var stores = {};
var countries = new Set(data.map(item => item.country).sort());
countries.forEach(country => {
var states = {};
var items = data.filter(item => item.country == country);
new Set(items.map(item => item.state).sort()).forEach(state => {
states[state] = items.filter(item => item.state == state)
.sort(item => item.state);
});
stores[country] = states;
});
console.log(stores['Australia']['Queensland']);
You can build the following country-state map by reducing the stores.
{
"Australia": {
"states": [
"New South Wales",
"Queensland"
]
},
"Indonesia": {
"states": [
"Java"
]
}
}
I reversed the order of the store data so that the sorting will actually make a difference.
let stores = sortByCountryAndState(getData())
let locations = groupByCountryAndState(stores)
console.log(locations)
function sortByCountryAndState(data) {
return data.sort((storeA, storeB) => {
if (storeA == null) return 1
if (storeB == null) return -1
let diff = storeA.country.localeCompare(storeB.country)
if (diff === 0) return storeA.state.localeCompare(storeB.state)
return diff
})
}
function groupByCountryAndState(data) {
return data.reduce((countries, store, index) => {
let country = countries[store.country] || {}
return Object.assign(countries, {
[store.country] : Object.assign(country, {
states : pushAndSort(country.states || [], store.state)
})
})
}, {})
}
function pushAndSort(arr, value) {
if (arr.indexOf(value) === -1) arr.push(value)
//return arr.sort() // Sorting is done before the grouping...
return arr
}
function getData() {
return [{
"id": 12314,
"storeName": "Store3",
"googleMapsUrl": "https://example3.com",
"country": "Indonesia",
"state": "Java"
}, {
"id": 12313,
"storeName": "Store2",
"googleMapsUrl": "https://example2.com",
"country": "Australia",
"state": "Queensland"
}, {
"id": 12312,
"storeName": "Store1",
"googleMapsUrl": "https://example1.com",
"country": "Australia",
"state": "New South Wales"
} ]
}
.as-console-wrapper { top: 0; max-height: 100% !important; }

Reduce flat array to 2-level nested json object array

I have the following flat array:
{ "State": "New York", "Name": "Jane", "Product": "Apple" },
{ "State": "New York", "Name": "Jill", "Product": "Banana"},
{ "State": "California", "Name": "Jill", "Product": "Apple" },
{ "State": "California", "Name": "Jill", "Product": "Banana"}
Is it possible to create a 2-level nested array (i.e., Name > nested State Array > nested Product Array)? It would look like as follows:
{
"Name": "Jill",
"States": [
{
"State": "California",
"Products": [
{
"Product": "Apple"
},
{
"Product": "Banana"
}
]
},
{
"State": "New York",
"Products": [
{
"Product": "Banana"
}
]
}
]
},
{
"Name": "Jane",
"States": [
{
"State": "New York",
"Products": [
{
"Product": "Apple"
}
]
}
]
}
I have been able to get one level nested (States). How would you nest the second level?
Here is a stackblitz: https://stackblitz.com/edit/angular-lu6zj2
this.grouped_data = this.data.reduce((data, item) => {
data[item.Name] = data[item.Name] || { Name: item.Name, States: []}
data[item.Name].States.push(item)
return data;
}, {})
let data = [
{ "State": "New York", "Name": "Jane", "Product": "Apple" },
{ "State": "New York", "Name": "Jill", "Product": "Banana"},
{ "State": "California", "Name": "Jill", "Product": "Apple" },
{ "State": "California", "Name": "Jill", "Product": "Banana"}
];
let grouped = data.reduce((p, n) => {
// Create the Lady
if (!p[n.Name]) p[n.Name] = { States: [] };
// Check if the state exists, if not create it, then push product into it
if (!p[n.Name].States.some(state => state.State === n.State)) {
p[n.Name].States.push({ State: n.State, Products: [n.Product] });
} else {
!p[n.Name].States.find(state => state.State === n.State).Products.push(n.Product);
}
return p;
}, {});
console.log(grouped);
After that you can also remove duplicated products if you want to. I'll let you deal with it !
EDIT I didn't respect your model, what a dumbass am I ... Here it is :
let data = [
{ "State": "New York", "Name": "Jane", "Product": "Apple" },
{ "State": "New York", "Name": "Jill", "Product": "Banana"},
{ "State": "California", "Name": "Jill", "Product": "Apple" },
{ "State": "California", "Name": "Jill", "Product": "Banana"}
];
let grouped = data.reduce((p, n) => {
// Create the Lady
if (!p.some(lady => lady.Name === n.Name)) p.push({ Name: n.Name, States: [] });
let lady = p.find(lady => lady.Name === n.Name);
// Check if the state exists, if not create it, then push product into it
if (!lady.States.some(state => state.State === n.State)) {
lady.States.push({ State: n.State, Products: [n.Product] });
} else {
lady.States.find(state => state.State === n.State).Products.push(n.Product);
}
return p;
}, []);
console.log(grouped);

Nested .unionWith, with one unique merge per level

Original data looks like that:
let AddressesBook = [
{
"userName": "Jay12",
"doorNumber": "1512",
"cityID": 19,
"city": "London",
"countryID": 1,
"country": "UK",
"houseType": "private"
},
{
"userName": "Jay12",
"doorNumber": "2003",
"cityID": 14,
"city": "York",
"countryID": 1,
"universe": "UK",
"houseType": "private"
},
{
"userName": "Jay12",
"doorNumber": "435",
"cityID": 31,
"city": "Washington",
"countryID": 2,
"universe": "USA",
"houseType": "private"
},
{
"userName": "Jay12",
"doorNumber": "1123",
"cityID": 18,
"city": "Oxford",
"countryID": 1,
"universe": "UK",
"houseType": "private"
}
];
i was mapping the data hierarchy by relevant unique ID using Lodash and
a suppurated dictionary:
function nestMaker(list, order) {
if (_.isEmpty(order)) return [];
let groups = _.groupBy(list, _.first(order));
return _.map(groups, (children, key) => {
let group = {};
group[_.first(order)] = key;
group.data = nestMaker(children, _.drop(order));
return _.isEmpty(group.data) ? _.omit(group, 'data') : group;
});
}
let hierarchical = nestMaker(AddressesBook, [
"countryID",
"cityID",
"houseType",
"doorNumber"]
);
it works fine, but i would like to have the name relevant to the id in each level of the object.
unfortunately you can't use _.groupBy on two keys. i was thinking about using _.unionWith separately from the first iteration but i couldn't find a way to use it recursively omitting the unnecessary data.
expected output:
let output =
[
{
"countryID": "1",
"country": "UK",
"data": [
{
"cityID": "14",
"city": "York",
"data": [
{
"houseType": "private",
"data": [
{
"doorNumber": "2003"
}
]
}
]
},
{
"cityID": "18",
"city": "Oxford",
"data": [
{
"houseType": "private",
"data": [
{
"doorNumber": "1123"
}
]
}
]
},
{
"cityID": "19",
"city": "London",
"data": [
{
"houseType": "private",
"data": [
{
"doorNumber": "1512"
}
]
}
]
}
]
},
{
"countryID": "2",
"country": "USA",
"data": [
{
"cityID": "31",
"city": "Washington",
"data": [
{
"houseType": "private",
"data": [
{
"doorNumber": "435"
}
]
}
]
}
]
}
];
You can get the 1st item in the group, and extract the name (country, city) from the item:
const AddressesBook = [{"userName":"Jay12","doorNumber":"1512","cityID":19,"city":"London","countryID":1,"country":"UK","houseType":"private"},{"userName":"Jay12","doorNumber":"2003","cityID":14,"city":"York","countryID":1,"country":"UK","houseType":"private"},{"userName":"Jay12","doorNumber":"435","cityID":31,"city":"Washington","countryID":2,"country":"USA","houseType":"private"},{"userName":"Jay12","doorNumber":"1123","cityID":18,"city":"Oxford","countryID":1,"country":"UK","houseType":"private"}];
const nestMaker = (list, order) => {
if (_.isEmpty(order)) return [];
const idKey = _.first(order);
const nameKey = idKey.replace('ID', '');
let groups = _.groupBy(list, idKey);
return _.map(groups, (children, key) => {
const group = {};
const child = _.first(children);
group[idKey] = key;
if(_.has(child, nameKey)) group[nameKey] = child[nameKey];
group.data = nestMaker(children, _.drop(order));
return _.isEmpty(group.data) ? _.omit(group, 'data') : group;
});
}
const hierarchical = nestMaker(AddressesBook, [
"countryID",
"cityID",
"houseType",
"doorNumber"
]);
console.log(hierarchical);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
If the id and the name keys are doesn't follow the same pattern, you can explicitly state them as entry in the order:
const AddressesBook = [{"userName":"Jay12","doorNumber":"1512","cityID":19,"city":"London","countryID":1,"universe":"UK","houseType":"private"},{"userName":"Jay12","doorNumber":"2003","cityID":14,"city":"York","countryID":1,"universe":"UK","houseType":"private"},{"userName":"Jay12","doorNumber":"435","cityID":31,"city":"Washington","countryID":2,"universe":"USA","houseType":"private"},{"userName":"Jay12","doorNumber":"1123","cityID":18,"city":"Oxford","countryID":1,"universe":"UK","houseType":"private"}];
const nestMaker = (list, order) => {
if (_.isEmpty(order)) return [];
const entry = _.first(order);
const [idKey, nameKey] = Array.isArray(entry) ? entry : [entry];
let groups = _.groupBy(list, idKey);
return _.map(groups, (children, key) => {
const group = {};
const child = _.first(children);
group[idKey] = key;
if(_.has(child, nameKey)) group[nameKey] = child[nameKey];
group.data = nestMaker(children, _.drop(order));
return _.isEmpty(group.data) ? _.omit(group, 'data') : group;
});
}
const hierarchical = nestMaker(AddressesBook, [
["countryID", "universe"],
["cityID", "city"],
"houseType",
"doorNumber"
]);
console.log(hierarchical);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
This is a bit manual but does the job.
let AddressesBook = [{
"userName": "Jay12",
"doorNumber": "1512",
"cityID": 19,
"city": "London",
"countryID": 1,
"country": "UK",
"houseType": "private"
},
{
"userName": "Jay12",
"doorNumber": "2003",
"cityID": 14,
"city": "York",
"countryID": 1,
"country": "UK",
"houseType": "private"
},
{
"userName": "Jay12",
"doorNumber": "435",
"cityID": 31,
"city": "Washington",
"countryID": 2,
"country": "USA",
"houseType": "private"
},
{
"userName": "Jay12",
"doorNumber": "1123",
"cityID": 18,
"city": "Oxford",
"countryID": 1,
"country": "UK",
"houseType": "private"
}
];
database = []
AddressesBook.forEach(a => {
doesExist = database.some(d => (d.countryID == a.countryID))
if (doesExist) {
let instance = database.filter(d => d.countryID == a.countryID)[0]
instance.data.push({
"cityID": a.cityID,
"city": a.city,
"data": [{
"houseType": a.houseType,
"data": [{
"doorNumber": a.doorNumber
}]
}]
})
} else {
database.push({
"countryID": a.countryID,
"country": a.country,
"data": [{
"cityID": a.cityID,
"city": a.city,
"data": [{
"houseType": a.houseType,
"data": [{
"doorNumber": a.doorNumber
}]
}]
}]
})
}
})
console.log(database)

Sort nested json complex array

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

Categories

Resources