I'm trying to process a json file and create a new one, but it does not work.
The structure of an old json is something like this:
[
{
"3":{
"value":2
},
"4":{
"value":1
}
},
{
"3":{
"value":6
},
"4":{
"value":1
}
}...and so on
What I'm trying to do is to create a new json object, which will have only two objects 0 and 1 and inside each of them there will be values from indexes 3 and 4 from the old one, which should look something like this:
{
"0":{
"0":[
{
"0":2
}
],
"1":[
{
"0":6
}
]..and so on
},
"1":{
"0":[
{
"0":1
}
],
"1":[
{
"0":1
}
]..and so on
}
}
The problem is that when I process and cook the old json the output for both indexes(0,1) is the same. I'm trying to loop it through 3 and 4 and assign those values into the new array but something is not quite right.
Fraction of the code:
//loop through the keysIndex
for (var c in keysIndex) {
//the new json has to be 2 objects, hence the below
newData[c] = {};
var vallueArr = [];
var newObj = {
0: oldData[i][keysIndex[c]].value
}
vallueArr.push(newObj);
objInNewData[entries] = vallueArr;
//the problem is somehwere here, it is appending twice the same
//objInNewData and not both 3 and 4 individually
newData[c] = objInNewData;
}
Hers's the whole logic: PLUNKER
Can someone please help as I cannot get my head around this :(
Many thanks
As I mentioned above, the use of index of keys of objects is not a good idea, because objects in Javascript have no defined order. For ordered items I suggest to use an array instead.
var data = [
{
"3": { "value": 2 },
"4": { "value": 1 }
}, {
"3": { "value": 6 },
"4": { "value": 1 }
}
],
keys = Object.keys(data[0]), // <-- ATTENTION!
obj = {};
data.forEach(function (a, i) {
keys.forEach(function (k, j) {
obj[j] = obj[j] || {};
obj[j][i] = obj[j][i] || [];
obj[j][i].push({ '0': a[k].value });
});
});
document.write('<pre>' + JSON.stringify(obj, 0, 4) + '</pre>');
Related
I have an array of objects:
var items = [
{
"id":"sugar",
"type": 'eatables'
},
{
"id":"petrol",
"type": 'utility'
},
{
"id":"apple",
"type": 'fruits'
},
{
"id":"mango",
"type": 'fruits'
},
{
"id":"book",
"type": 'education'
}
];
Now I have another array of orders with the help of which I want to sort items array:
var orders = [
{
"id":"sugar",
"order":5
},
{
"id":"book",
"order":1
}
];
Now what I am trying so far in my logic is that I am putting so many loops that it is totally creating mess.
Can anyone suggest me with a short and optimized logic for this?
One approach could be creating one dictionary which will keep the order for every element. Also, I've iterated the whole items array to store the position for the elements that are not in the orders array.
First of all, I'll declare one array which keep the whole orders, thus one array with 1..N elements.
var orderNumbers = Array.from({length: items.length}, (_, v) => v + 1);
Then I started to create the dictionary by iterating orders array and remove orders from orderNumbers.
The last step is iterating the items array and use shift method to "pop" the first element.
The final dictionary will look like
{
"sugar": 2,
"book": 3,
"petrol": 1,
"apple": 4,
"mango": 5
}
In this code I used one dictionary because its lookup has complexity of O(1).
var items = [ { "id":"sugar", "type": 'eatables' }, { "id":"petrol", "type": 'utility' }, { "id":"apple", "type": 'fruits' }, { "id":"mango", "type": 'fruits' }, { "id":"book", "type": 'education' } ], orders = [ { "id":"sugar", "order":2 }, { "id":"book", "order":3 } ], orderNumbers = Array.from({length: items.length}, (_, v) => v + 1);
var ordersDict = orders.reduce((acc, item) => {
acc[item.id] = item.order;
//remove from order numbers
let index = orderNumbers.findIndex(el => el == item.order);
orderNumbers.splice(index, 1);
return acc;
}, {});
for(let i = 0; i < items.length; i++){
if(!ordersDict.hasOwnProperty(items[i].id)){
ordersDict[items[i].id] = orderNumbers[0];
orderNumbers.shift();
}
}
//sort the array
items.sort((a,b) => ordersDict[a.id] - ordersDict[b.id]);
console.log(items);
let oorder = new Object();
orders.map(item=>{oorder[item.id]=item.order});
var new_items = [];
items.map(item=>{new_items[oorder[item.id]-1]=item});
I have 2 lists - nodes and links... Now what I would want is the most efficient way to add all the directly/indirectly linked elements into different groups.... For eg, 0 is connected to 1 which is connected to 2 so nodes 0,1,2 become group 1.... node 3 is connected to 4 so it becomes group 2 and so on.... Thanks in advance for your help :) This is part of a d3 implementation am doing..
PS: These lists will easily be in tens of thousands of nodes and links.
"nodes":[
{
"id":0,
"x":1509.9862,
"y":-609.1013
},
{
"id":1,
"x":1645.9578,
"y":-85.06705
},
{
"id":2,
"x":1948.1533,
"y":-469.3646
},
{
"id":3,
"x":348.1533,
"y":-669.3646
},
{
"id":4,
"x":1448.1533,
"y":-1469.3646
}
...
]
"links":[
{
"from":0,
"to":1
},
{
"from":1,
"to":2
},
{
"from":3,
"to":4
}
...
]
This is a classic UnionFind problem. The idea is to see each node as a set that has a pointer point to its father. Nodes with the same father are in the same group. So for your problem, we can create n sets at the beginning. And then iterate through the link to group everyone connected by the same link. The complexity is O(n), where n is the number of nodes.
nodes = [{
"id": 0,
"x": 1509.9862,
"y": -609.1013
},
{
"id": 1,
"x": 1645.9578,
"y": -85.06705
},
{
"id": 2,
"x": 1948.1533,
"y": -469.3646
},
{
"id": 3,
"x": 348.1533,
"y": -669.3646
},
{
"id": 4,
"x": 1448.1533,
"y": -1469.3646
}
];
links = [{
"from": 0,
"to": 1
},
{
"from": 1,
"to": 2
},
{
"from": 3,
"to": 4
}
];
// union-find is a data structure that can union two sets and check
// whether two element in the same set.
var father = {};
function group(nodes, links) {
// create n set with each set has the node as its only element
nodes.forEach(function(node, i) {
father[node.id] = node.id;
});
// union each set that has a link between them
links.forEach(function(link, i) {
union(link.from, link.to);
});
// for each unioned set, group nodes together
var id = 1;
var groupIdCnt = {};
var groupIds = {};
nodes.forEach(function(node, i) {
var f = find(node.id);
if (typeof groupIds[f] === 'undefined') {
groupIds[f] = id;
groupIdCnt[id] = 1;
id++;
} else {
groupIdCnt[groupIds[f]]++;
}
});
var groups = {};
nodes.forEach(function(node, i) {
var f = find(node.id);
if (groupIdCnt[groupIds[f]] === 1) {
node['group'] = 0;
} else {
node['group'] = groupIds[f];
}
if (typeof groups[node['group']] === 'undefined') {
groups[node['group']] = [];
}
groups[node['group']].push(node);
});
return Object.values(groups);
}
// find father of each set
function find(node) {
// if it is the root, return
if (father[node] === node) {
return node;
}
// if not, find the father and point to it
father[node] = find(father[node]);
return father[node];
}
// update the father of set which includes node1 to the father of set which includes node 2
function union(node1, node2) {
father[find(node1)] = find(node2);
}
// O(n), since we visit each node once
var groups = group(nodes, links);
console.log(nodes);
console.log(groups);
This code spits out an object whose keys are the node id and whose values are a group id, not necessarily sequential.
var obj = {
"links":[
{
"from":0,
"to":1
},
{
"from":1,
"to":2
},
{
"from":5,
"to":4
},
{
"from":3,
"to":4
}
]
};
var groups = {};
var nextGrp = 1;
for (var i=0, l; l = obj.links[i]; i++) {
if (groups[l.from]) {
if (groups[l.to]) {
if (groups[l.to] != groups[l.from]) {
// the two items span two different groups which must now be joined into 1
for (var j in groups) {
if (groups[j] == groups[l.to]) {
groups[j] = groups[l.from];
}
}
}
} else {
groups[l.to] = groups[l.from];
}
} else if (groups[l.to]) {
groups[l.from] = groups[l.to];
} else {
groups[l.from] = nextGrp;
groups[l.to] = nextGrp;
nextGrp++;
}
}
console.log(groups);
In the solution below I am creating groups of links that are, well, linked to each other. I do so by looping through all of the from/to combinations, and finding out if either has already been added to any of the accumulating groups of links. If they have, then I just add (or re-add) both the from and to value to that group. If neither the from nor to value has yet been grouped, then I make a new group and add both the from and to values to it. Note that these "groups" are actually Javascript sets, a new ES6/ES2015 data type that makes it much easier to deal with "groups" of elements for which no duplicates are needed and/or allowed.
Once the groups/sets of links are established, I then simply add an attribute to each node that indicates which group of links it is a part of.
Note that, for the sake of this demo code, I've simplified/de-cluttered some node values. I've also added some extra links, just to demonstrate some further cases that need handling.
const groupNodes = (nodes, links) => {
const groups = links.reduce((grps, {from, to}) => {
if (!grps.some(grp => {
if (grp.has(from) || grp.has(to)) return grp.add(from).add(to);
})) grps.push(new Set([from, to]));
return grps;
}, []);
nodes.forEach(node => {
groups.forEach((grp, i) => { if (grp.has(node.id)) node.group = i; });
});
return nodes;
};
const nodes = [
{
"id":0,
"x":0,
"y":0
},
{
"id":1,
"x":11,
"y":-11
},
{
"id":2,
"x":22,
"y":-22
},
{
"id":3,
"x":33,
"y":-33
},
{
"id":4,
"x":44,
"y":-44
},
{
"id":5,
"x":55,
"y":-55
},
{
"id":6,
"x":66,
"y":-66
}
];
const links = [
{
"from": 0,
"to" : 1
},
{
"from": 1,
"to" : 2
},
{
"from": 2,
"to" : 0
},
{
"from": 3,
"to" : 4
},
{
"from": 4,
"to" : 5
},
{
"from": 6,
"to" : 0
}
];
console.log(JSON.stringify(groupNodes(nodes, links)));
This question already has answers here:
Convert array of object to object with keys
(2 answers)
Closed 6 years ago.
One of the possible outputs for my service is as follows.
[{
"key": 1,
"val": 0
}, {
"key": 2,
"val": 0
}]
Is there a function that can convert this to an object like the one below?
{
"1":0,
"2":0
}
My purpose is to be able to read the object values as a map, such as o["1"], i.e.: if (o["1"] == 0) {....
You can do this with reduce
var data = [{"key": 1, "val": 0}, {"key": 2, "val": 0}];
var result = data.reduce((obj, e) => {
obj[e.key]= e.val;
return obj;
}, {});
console.log(result)
You could iterate over with Array#forEach and assign the wanted properties with the value.
var array = [{ "key": 1, "val": 0 }, { "key": 2, "val": 0 }],
object = {};
array.forEach(function (a) {
object[a.key] = a.val;
});
document.write('<pre>' + JSON.stringify(object, 0, 4) + '</pre>');
You can do it in javascript with
target = {};
source.forEach(function(e) {
target[e.key] = e.val;
});
I don't think there is one in pure Javascript. Maybe some library like jQuery will have something like that. You can do your own with little code, though. In pure JS:
var o = {};
for (var i = 0; i < json.length; i++) {
o[json[i].key] = json[i].val;
}
I have data that's in this format:
{
"columns": [
{
"values": [
{
"data": [
"Project Name",
"Owner",
"Creation Date",
"Completed Tasks"
]
}
]
}
],
"rows": [
{
"values": [
{
"data": [
"My Project 1",
"Franklin",
"7/1/2015",
"387"
]
}
]
},
{
"values": [
{
"data": [
"My Project 2",
"Beth",
"7/12/2015",
"402"
]
}
]
}
]
}
Is there some super short/easy way I can format it like so:
{
"projects": [
{
"projectName": "My Project 1",
"owner": "Franklin",
"creationDate": "7/1/2015",
"completedTasks": "387"
},
{
"projectName": "My Project 2",
"owner": "Beth",
"creationDate": "7/12/2015",
"completedTasks": "402"
}
]
}
I've already got the column name translation code:
r = s.replace(/\%/g, 'Perc')
.replace(/^[0-9A-Z]/g, function (x) {
return x.toLowerCase();
}).replace(/[\(\)\s]/g, '');
Before I dive into this with a bunch of forEach loops, I was wondering if there was a super quick way to transform this. I'm open to using libraries such as Underscore.
function translate(str) {
return str.replace(/\%/g, 'Perc')
.replace(/^[0-9A-Z]/g, function (x) {
return x.toLowerCase();
})
.replace(/[\(\)\s]/g, '');
}
function newFormat(obj) {
// grab the column names
var colNames = obj.columns[0].values[0].data;
// create a new temporary array
var out = [];
var rows = obj.rows;
// loop over the rows
rows.forEach(function (row) {
var record = row.values[0].data;
// create a new object, loop over the existing array elements
// and add them to the object using the column names as keys
var newRec = {};
for (var i = 0, l = record.length; i < l; i++) {
newRec[translate(colNames[i])] = record[i];
}
// push the new object to the array
out.push(newRec);
});
// return the final object
return { projects: out };
}
DEMO
There is no easy way, and this is really not that complex of an operation, even using for loops. I don't know why you would want to use regex to do this.
I would start with reading out the column values into a numerically indexed array.
So something like:
var sourceData = JSON.parse(yourJSONstring);
var columns = sourceData.columns[0].values[0].data;
Now you have a convenient way to start building your desired object. You can use the columns array created above to provide property key labels in your final object.
var sourceRows = sourceData.rows;
var finalData = {
"projects": []
};
// iterate through rows and write to object
for (i = 0; i < sourceRows.length; i++) {
var sourceRow = sourceRows[i].values.data;
// load data from row in finalData object
for (j = 0; j < sourceRow.length; j++) {
finalData.projects[i][columns[j]] = sourceRow[j];
}
}
That should do the trick for you.
I have two js arrays already, say: names and values (with the same length), now I would like to construct a json object in certain format? For example:
names = ["label1","label2","label3"];
values = [[[0,1],[1,9],[2,10]],[[0,89],[1,91],[2,1]],[[0,1],[1,9],[2,10]]];
I would like to have a json array data_spec in this format:
[{
label:"label1",
data:[[0,1],[1,9],[2,10]]
},
{
label:"label2",
data:[[0,89],[1,91],[2,1]]
},
{
label:"label3",
data:[[0,1],[1,9],[2,10]]
}]
Could anyone tell one how? Thanks a lot!
For a bit of variety and a check,
var data_spec = [];
if (names.length != values.length) {
// panic, throw an exception, log an error or just return an empty array
} else {
for (var i=0, name; name = names[i]; i++) { // assuming a non-sparse array
data_spec[i] = {
label : name,
data : values[i]
};
}
}
That is, non-sparse and not containing anything else that would evaluate to false.
If your framework has an each function added to Array and you don't care about performance,
var data_spec = [];
names.each(function(name) {
data_spec.push({ label : name, data : values[names.indexOf(name)] });
});
If your framework is a clean one like Dojo and puts it somewhere else (ex is Dojo),
var data_spec = [];
dojo.forEach(names, function(name) {
data_spec.push({ label : name, data : values[names.indexOf(name)] });
});
If your framework has an each function that returns an Array of identical length with the results of every operation at their expected position,
var data_spec = arrayOfResultsEach(names, function(name) {
return { label : name, data : values[names.indexOf(name)] };
});
These are just for illustration, indexOf inside loops of arbitrary length is a major code smell.
Just use a loop (make sure the two arrays are of same length)
result = [];
for(var i=0, len=names.length; i < len; i++) {
result.push({label: names[i], data: values[i]});
}
var myArray =
[{
"label": "label1",
"data" :
{
"0": "1",
"1": "9",
"2": "10"
}
},
{
"label": "label2",
"data" :
{
"0": "89",
"1": "91",
"2": "1"
}
},
{
"label": "label3",
"data" :
{
"0": "1",
"1": "9",
"2": "10"
}
}];
alert(myArray[0].data[2]);