Nested JSON string to dictionary with object to be used as key - javascript

I am loading a nested JSON query and I am trying to create a dictionary that will have a specific object as a key. Sp, in my case, the key will be the country and then each dictionary value will have the date and the number. I have made a progress but I am stuck at the final function. My snippet prints all the steps in the HTML part.
So, I am actually trying to convert this:
2018-05-01,Italy,25,2018-04-01,Italy,37,2018-05-01,France,30,2018-04-01,France,90
to this:
{"Italy":[{"Date":"2018-04-01","num":37},{"Date":"2018-05-01","num":25}],"France":[{"Date":"2018-04-01","num":90},{"Date":"2018-05-01","num":30}]}
which will then be converted to:
[
{
"Value": "Italy",
"num": 37,
"num2": 25
},
{
"Value": "France",
"num": 90,
"num2": 30
}
]
where num will have the number of the first date and num2 will have the number of the second date.
Also, feel free to provide a completely different solution if you believe that my steps are too many.
var json_data = {"headers":["Month","Country","Number"],"rows":[["2018-05-01","Italy",25],["2018-04-01","Italy",37],["2018-05-01","France",30],["2018-04-01","France",90]
]};
var dataRows = json_data.rows;
document.getElementById("yellow").innerHTML = dataRows;
//Returns unique values of a specific object of a JSON string
uniqueValues = (data,objectNum) => {
var uniqueValues = [];
data.forEach(function(item) {
var value = item[objectNum];
if (uniqueValues.indexOf(value) !== -1)
return false;
uniqueValues.push(value);
});
return uniqueValues;
}
var uniqueCountries = uniqueValues(dataRows,1);
document.getElementById("green").innerHTML = uniqueCountries;
var uniqueDates = uniqueValues(dataRows,0);
document.getElementById("blue").innerHTML = uniqueDates;
//Create dictionary function (transformed JSON)
createDict = (data,objectNum) => {
var dict =[];
var num = 0;
var num2 = 0;
for (i = 0; i < dataRows.length; i++)
{
var object = {"Date": dataRows[i][0].slice(0,10), "Value": dataRows[i][1], "num": dataRows[i][2]};
dict.push(object);
}
return dict;
}
var dictData = createDict(dataRows,2);
document.getElementById("orange").innerHTML = JSON.stringify(dictData);
//Function that will return the final output
function test (){
var sumMetric = {};
dictData.forEach(function(d) {
uniqueCountries.forEach(function(country) {
console.log(d.Date);
//d.num = +d.num;
sumMetric[country] = [];
uniqueDates.forEach(function(element) {
sumMetric[country].push({Date: d.Date, num: d.num});
});
});
});
document.getElementById("red").innerHTML =JSON.stringify(sumMetric);
return sumMetric;
}
test();
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js" charset="utf-8"></script>
<h4>Original JSON</h4>
<div style="background:yellow;" id="yellow"></div>
<h4>Unique Countries</h4>
<div style="background:green; color:white" id="green"></div>
<h4>Unique Dates</h4>
<div style="background:blue; color:white" id="blue"></div>
<h4>Dictionary Creation</h4>
<div style="background:orange;" id="orange"></div>
<h4>Wrong Output</h4>
<div style="background:red;" id="red"></div>
<h4>Expected Output</h4>
<div style="background:purple; color:white" id="purple">{"Italy":[{"Date":"2018-04-01","num":37},{"Date":"2018-05-01","num":25}],"France":[{"Date":"2018-04-01","num":90},{"Date":"2018-05-01","num":30}]}</div>
<h4>Final Output that I need</h4>
<div style="background:grey; color:black" id="purple">[
{
"Value": "Italy",
"num": 37,
"num2": 25
},
{
"Value": "France",
"num": 90,
"num2": 30
}
]<div>

Assuming that the array of arrays in your snippet is the correct input dataset to start with (rather than the string posted at the beginning of your question)...
If the original array is guaranteed to only have 2 sub-arrays for each country, then you can use reduce to group it into an object by country key and then compare the array pairs in the grouped object to produce the desired results. For example:
const data = [["2018-05-01", "Italy", 25], ["2018-04-01", "Italy", 37], ["2018-05-01", "France", 30], ["2018-04-01", "France", 90]];
const groups = data.reduce((acc, arr) => {
if (acc.hasOwnProperty(arr[1])) {
acc[arr[1]].push(arr);
} else {
acc[arr[1]] = [arr];
}
return acc;
}, {});
let results = [];
for (const g in groups) {
const obj = { value: g };
const a = groups[g][0];
const b = groups[g][1];
if (a[0] <= b[0]) {
obj.num = a[2];
obj.num2 = b[2];
} else {
obj.num = b[2];
obj.num2 = a[2];
}
results.push(obj);
}
console.log(results);
If the original array is not guaranteed to have only 2 sub-arrays for each country, then you would have to modify the for...in loop above to loop through and compare multiple country arrays (rather than just comparing a single pair) and update the result objects as needed.

Related

how to make object's array from several array

For example,
I have a total of two arrangements.
The key array has keys.
The remaining arrays are multi arrays in one array like [[A], [B], [C], ...]
So how do we put objects in one array?
let key = [“name”, “age”, “country”];
let values = [["james", "23", "US"],["steve", "20", "UK"], ...]
** expect result **
result = [
{
"name": "james",
"age": 23,
"country": "US"
},
{
"name": "steve",
"age": 20,
"country": "UK"
},
...
]
Single line using array map and reduce functions:
values.map(v=>(key.reduce((acc, k, i) => ({...acc, [k]: v[i]}), {})));
(Note your original question contains non-ASCII quotation marks “” - you need to use " for valid JS syntax).
if you have data as name age and country with same keys so you can try below code it should work for you.
let values = [["james", "23", "US"],["steve", "20", "UK"], ...]
const result = [];
values.forEach(item => {
const [name, age, country] = item;
result.push({ name, age, country });
});
console.log(result)
I just asked your question to OpenAI JavaScript Codex and it returned this result.
/* let key = [“name”, “age”, “country”]; */
var key = ["name", "age", "country"];
/* let values = [["james", "23", "US"],["steve", "20", "UK"]] */
var values = [["james", "23", "US"],["steve", "20", "UK"]];
/* So how do we put objects in one array? */
var objects = [];
for (var i = 0; i < values.length; i++) {
var object = {};
for (var j = 0; j < key.length; j++) {
object[key[j]] = values[i][j];
}
objects.push(object);
}
I really don't know if it works or not, but I am curious to see what it does. You should try this.
Please forgive me if it doesn't work. Thanks
const objs = values.map(
(valSet) =>
Object.fromEntries(
valSet.map(
(val,i) => [val,keys[i]]
)
)
);
make entry arrays and then use this

How to group an array on an attribute to attain each groups aggregate value at a specific key using javascript?

I'd like to take the below array and identify all the unique values of 'fruit', and identify the corresponding counts for those fruit.
For example, in the below array, we know that there are three fruit (apples, bananas, and cherries) and that we have 2 apples, 10 bananas, and 5 cherries.
var input_data = [{"count":1,"fruit":"apple"},{"count":1,"fruit":"apple"},{"count":10,"fruit":"banana"},{"count":5,"fruit":"cherry"}]
Based on the above input, I'd like to achieve the below outputs:
desired_output_1 = ['apple','banana','cherry']
desired_output_2 = [2,10,5]
I was able to get desired_output_1 with the following function that I used from underscore.js, but I'm not sure how to attain desired_output_2.
_.uniq(_.pluck(input_data,'fruit'))
As a result, I really would like a way to attain [2,10,5] based on count for the above.
var data = [{
"count": 1,
"fruit": "apple"
}, {
"count": 1,
"fruit": "apple"
}, {
"count": 10,
"fruit": "banana"
}, {
"count": 5,
"fruit": "cherry"
}];
var fruits = [];
var counts = [];
for (var i in data) {
var index = fruits.indexOf(data[i].fruit);
if (index == -1) {
fruits.push(data[i].fruit)
counts.push(data[i].count);
} else {
counts[index] = counts[index] + data[i].count;
}
}
console.log(fruits , counts);
You may not need underscore/lodash :)
var input_data = [
{"count":1,"fruit":"apple"},
{"count":1,"fruit":"apple"},
{"count":10,"fruit":"banana"},
{"count":5,"fruit":"cherry"}
];
var result = input_data.reduce(function ( acc, current ) {
if( !acc[current.fruit] ) {
acc[current.fruit] = 0;
}
acc[current.fruit] += current.count;
return acc;
}, {});
console.log(result);
Output is an object instead of two arrays. This will keep the fruit <-> count relation.
var input_data = [{"count":1,"fruit":"apple"},{"count":1,"fruit":"apple"},{"count":10,"fruit":"banana"},{"count":5,"fruit":"cherry"}];
var fruits = [];
var counts = [];
for (var i in input_data) {
var index = fruits.indexOf(input_data[i].fruit);
if (index == -1) {
fruits.push(input_data[i].fruit)
counts.push(input_data[i].count);
} else {
counts[index] += input_data[i].count;
}
}
console.log(fruits, counts);

merging two array of objects with custom compare function with javascript

I have two array of objects like:
var A = [{title:"name1",count:5},{title:"name2",count:1},{title:"name3",count:3}];
and:
var B = [{title:"name2",count:7},{title:"name3",count:2},{title:"name4",count:3},{title:"name5",count:8}];
I need to merge this two array in one array and sum the "count" values in returned array when the "title" properties is same:
the last answer must be:
[{title:"name1",count:5},{title:"name2",count:8},{title:"name3",count:5},{title:"name4",count:3},{title:"name5",count:8}]
how can i do this???
You can use Array#forEach and Array#some to achieve a result
var M = A.concat(B)
var C = [];
M.forEach(function(a) {
var index;
if (C.some(function(c, i) { index = i; return a.title == c.title; })) {
C[index].count += a.count;
} else {
C.push(a);
}
});
console.log(C); // as you expect
Solution with Array.concat and Array.map functions:
var merged = A.concat(B), titles = [], result = [];
merged.map(function(obj){
if (titles.indexOf(obj.title) === -1) {
titles.push(obj.title);
result.push(obj);
} else {
result[titles.indexOf(obj.title)]['count'] += obj['count'];
}
});
console.log(result); // will output the expected array of objects
It can be done like this https://jsfiddle.net/menm9xeo/
var noMatch;
var A = [{title:"name1",count:5},{title:"name2",count:1},{title:"name3",count:3}];
var B = [{title:"name2",count:7},{title:"name3",count:2},{title:"name4",count:3},{title:"name5",count:8}];
//for each A, loop through B's. If a match is found combine the Counts in A.
for(var i=0;i<A.length;i++){
for(var j=0;j<B.length;j++){
if(A[i].title == B[j].title){
A[i].count += B[j].count;
}
}
}
//find all B's that were not combined with A in the previous step, and push them into A.
for(var i=0;i<B.length;i++){
noMatch = true;
for(var j=0;j<A.length;j++){
if(B[i].title == A[j].title){
B[i].count += A[j].count;
noMatch = false;
}
}
if(noMatch){A.push(B[i]);}
}
Heres a simple 3 line answer (minus the A/B vars); utilizes the fact that objects must have unique keys
var A = [{title:"name1",count:5},{title:"name2",count:1},{title:"name3",count:3}];
var B = [{title:"name2",count:7},{title:"name3",count:2},{title:"name4",count:3},{title:"name5",count:8}];
var o = {};
A.concat(B).forEach(function(a){o[a.title] = o.hasOwnProperty(a.title)? o[a.title]+a.count: a.count});
var AB = Object.keys(o).map(function(j){ return {title:j,count:o[j]} });
This proposal is merging and counting with a temporary object and Array#forEach()
The forEach() method executes a provided function once per array element.
var arrayA = [{ title: "name1", count: 5 }, { title: "name2", count: 1 }, { title: "name3", count: 3 }],
arrayB = [{ title: "name2", count: 7 }, { title: "name3", count: 2 }, { title: "name4", count: 3 }, { title: "name5", count: 8 }],
result = function (array) {
var o = {}, r = [];
array.forEach(function (a) {
if (!(a.title in o)) {
o[a.title] = { title: a.title, count: 0 };
r.push(o[a.title]);
}
o[a.title].count += a.count;
});
return r;
}(arrayA.concat(arrayB));
document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');
Using lodash ._concat function :
var result = _.concat(A, B);
Fiddle

Remove duplicates from array of arrays by the first object

I have an array of arrays which looks like this:
arr = [
["Bob","USA","55"],
["Frank","Canada","20"],
["Bob","UK","35"],
["Bob","France","38"],
["Anna","Poland","22"]
]
I like to remove duplicate arrays which have the same value on the first position(the same name) - so I'd like to my output will look like that:
arr = [
["Bob","USA","55"],
["Frank","Canada","20"],
["Anna","Poland","22"]
]
I'm trying to do this in this way:
uniqueArr = []
for (var i in arr) {
if (uniqueArr.indexOf(arr[i][0]) === -1)) {
uniqueArr.push(arr[i][0])
}
Everything works ok - my output looks like Bob, Frank, Anna
But the problem is when I'm trying to recive whole arrays with unique value name. When I'm doing:
uniqueArr = []
for (var i in arr) {
if (uniqueArr.indexOf(arr[i][0]) === -1)) {
uniqueArr.push(arr[i])
}
My output looks exactly like the input array. Do you know where I'm doing wrong?
You could keep track of the key string in a separate array and track that instead, for example:
var uniqueArr = [],
keys = []; // Create an array for storing the key values
for (var i in arr) {
if (keys.indexOf(arr[i][0]) === -1) {
uniqueArr.push(arr[i]); // Push the value onto the unique array
keys.push(arr[i][0]); // Push the key onto the 'key' array
}
}
console.log(uniqueArr);
jsFiddle example
try
arr = [
["Bob", "USA", "55"],
["Frank", "Canada", "20"],
["Bob", "UK", "35"],
["Bob", "France", "38"],
["Anna", "Poland", "22"]
]
var newArr = [];
for (var i = 0; i < arr.length; i++) {
if (isInArr(newArr, arr[i]) == -1) {
newArr.push(arr[i]);
}
}
function isInArr(checkArr, value) {
var index = -1;
for (var i = 0; i < checkArr.length; i++) {
if (checkArr[i][0] == value[0]) {
index = i;
break;
}
}
return index;
}
console.log(newArr)
DEMO
Take a look atthe function unique2. It works!
originalArr = [
["Bob", "USA", "55"],
["Frank", "Canada", "20"],
["Bob", "UK", "35"],
["Bob", "France", "38"],
["Anna", "Poland", "22"]
];
function unique(arr) {
uniqueArr = [];
for (var i in arr) {
if (uniqueArr.indexOf(arr[i][0]) === -1) {
uniqueArr.push(arr[i]);
}
}
return uniqueArr;
}
function unique2(arr) {
uniqueArr = [];
keys = [];
for (var i in arr) {
if (keys.indexOf(arr[i][0]) === -1) {
uniqueArr.push(arr[i]);
keys.push(arr[i][0]);
}
}
return uniqueArr;
}
var response = document.getElementById('response');
response.textContent = JSON.stringify(unique(originalArr));
var response2 = document.getElementById('response2');
response2.textContent = JSON.stringify(unique2(originalArr));
<h1>Your code</h1>
<div id="response"></div>
<h1>My code</h1>
<div id="response2"></div>

How to merge JSON objects using JavaScript?

How to merge JSON objects using plain(without jQuery) JavaScript?
Requirement is to:
Convert from:
chartData=[
{"date":"2014-05-1","CAT1":0.1},
{"date":"2014-05-1","CAT2":0.2},
{"date":"2014-05-1","CAT3":0.3},
{"date":"2014-05-1","UNSET":0.4},
{"date":"2014-05-2","CAT1":0.4},
{"date":"2014-05-2","CAT2":0.3},
{"date":"2014-05-2","CAT3":0.2},
{"date":"2014-05-2","UNSET":0.1}
];
Convert To:
chartData=[
{"date":"2014-05-1","CAT1":0.1,"CAT2":0.2,"CAT3":0.3,"UNSET":0.4},
{"date":"2014-05-2","CAT1":0.4,"CAT2":0.3,"CAT3":0.2,"UNSET":0.1}
]
Here's an example of how to do this... no jquery required.
chartData=[{"date":"2014-05-1","CAT1":0.1},{"date":"2014-05-1","CAT2":0.2},{"date":"2014-05-1","CAT3":0.3},{"date":"2014-05-1","UNSET":0.4},{"date":"2014-05-2","CAT1":0.4},{"date":"2014-05-2","CAT2":0.3},{"date":"2014-05-2","CAT3":0.2},{"date":"2014-05-2","UNSET":0.1}];
function groupProps(orig, key) {
var newArr = [],
groups = {},
newItem, i, j, cur;
for (i = 0, j = orig.length; i < j; i++) {
cur = orig[i];
if (!(cur[key] in groups)) {
groups[cur[key]] = {date: cur[key] };
newArr.push(groups[cur[key]]);
}
for (var prop in cur) {
if (prop != key) {
groups[cur[key]][prop] = cur[prop];
}
}
}
return newArr;
}
console.log(groupProps(chartData, "date"))
Here we iterate backwards through the chartData array operating in place and splicing elements out of the array as the content is merged :
var chartData=[{"date":"2014-05-1","CAT1":0.1},{"date":"2014-05-1","CAT2":0.2},{"date":"2014-05-1","CAT3":0.3},{"date":"2014-05-1","UNSET":0.4}, {"date":"2014-05-2","CAT1":0.4},{"date":"2014-05-2","CAT2":0.3},{"date":"2014-05-2","CAT3":0.2},{"date":"2014-05-2","UNSET":0.1}];
var chartDates = {}; /* stores references to elements for each date */
for (var i=chartData.length-1; i >= 0; i--) {
var date = chartData[i]['date'];
if (date in chartDates) {
for (var k in chartData[i]) {
chartDates[date][k] = chartData[i][k];
}
chartData.splice(i,1);
} else {
chartDates[date] = chartData[i];
}
}
console.log(chartData);
Here is some code that will do it, we first loop through the array to group all of the non-date properties together by date. then append the date property to that intermediate result:
var chartData = [
{"date": "2014-05-1", "CAT1": 0.1},
{"date": "2014-05-1", "CAT2": 0.2},
{"date": "2014-05-1", "CAT3": 0.3},
{"date": "2014-05-1", "UNSET": 0.4},
{"date": "2014-05-2", "CAT1": 0.4},
{"date": "2014-05-2", "CAT2": 0.3},
{"date": "2014-05-2", "CAT3": 0.2},
{"date": "2014-05-2", "UNSET": 0.1}
];
function mergeValues(chartData) {
var tempObj = {};
for (i in chartData) {
var date = chartData[i].date;
//remove the date
delete chartData[i].date;
//get the remaining keys
var keys = Object.keys(chartData[i]);
tempObj[date] = tempObj[date] || {};
for (j in keys) {
tempObj[date][keys[j]] = chartData[i][keys[j]];
}
}
console.log(tempObj);
//{"2014-05-1":{ CAT1:0.1, CAT2:0.2, CAT3:0.3, UNSET:0.4}
//{"2014-05-2":{ CAT1:0.4, CAT2:0.3, CAT3:0.2, UNSET:0.1}
var arr = [];
var keys = Object.keys(tempObj);
for (k in keys) {
var obj = tempObj[keys[k]];
//add the date
obj.date = keys[k];
arr.push(obj);
}
return arr;
}
console.log(mergeValues(chartData));
//
//[
// {"CAT1":0.1,"CAT2":0.2,"CAT3":0.3,"UNSET":0.4,"date":"2014-05-1"},
// {"CAT1":0.4,"CAT2":0.3,"CAT3":0.2,"UNSET":0.1,"date":"2014-05-1"}
//]
Using underscore.js, it can be done pretty easily:
var groupedBy = _.groupBy(chartData, 'date');
var a = _.reduce(groupedBy, function(a, c) {
a.push(_.reduce(c, function(a2, c2){
for(var i in c2) { a2[i] = c2[i]; }
return a2;
}, { }));
return a;
},[]); // 'a' holds the desired merged object

Categories

Resources