Sort complex JSON based on particular key - javascript

I have a JSON object with the following format:
{
items:{
nestedObj:{
position:3
},
nestedObj2:{
position:1
},
nestedObj3:{
position:2,
items:{
dblNestedObj:{
position:2
},
dblNestedObj2:{
position:3
},
dblNestedObj3:{
position:1
}
}
}
}
}
I am attempting to sort each level of nested object by their position attribute. I can recursively iterate the object, but I don't know where to start for sorting it...

Unfortunately it's not quite so easy to use the sort method as it would if you had an array. So let's build an array:
var tmp = [], x;
for( x in obj.items) { // assuming your main object is called obj
tmp.push([x,obj.items[x].position]);
// here we add a pair to the array, holding the key and the value
}
// now we can use sort()
tmp.sort(function(a,b) {return a[1]-b[1];}); // sort by the value
// and now apply the sort order to the object
var neworder = {}, l = tmp.length, i;
for( i=0; i<l; i++) neworder[tmp[i][0]] = obj.items[tmp[i][0]];
obj.items = neworder;

Related

convert array of objects into simple array nodejs

I am creating project using nodejs. I want to convert array of objects into simple array.For example
var test = [ { id: '1111',
type: 'sdfsdf'
},
{ id: 'df45',
type: 'fsdsdf',
}]
I need
var actual = [111,'sdfsdf'], ['df45','fsdsdf'].
I would propose this solution based on a dynamic number of keys:
var arr = test.map(function(obj){
return Object.keys(obj). // convert object to array of keys
reduce(function(arr, current){arr.push(obj[current]); return arr}, []); // generate a new array based on object values
});
This can be done using Array.map() as follows:
var actual = []
test.map(function(object) {
actual.push(objectToArray(object))
})
function objectToArray(obj) {
var array = []
// As georg suggested, this gets a list of the keys
// of the object and sorts them, and adds them to an array
var obj_keys = Object.keys(obj).sort()
// here we iterate over the list of keys
// and add the corresponding properties from the object
// to the 'array' that will be returned
for(var i = 0; i < obj_keys.length; i++) {
array.push(obj[obj_keys[i]])
}
return array
}
The function objectToArray takes any object and turns it into an array so that it can be flexible regardless of the keys within the object.

pushing strings into an object

I have an array of objects and an array of string and I am tying to combine the two in sequence meaning I would like to first item on the array to be stored only in the first object, second item of the array only in the second object, ect. Something like the following.
var objects = [ obj1, obj2, obj3];
var strings = ["123", "456", "789"];
//Result
var results = [
{
"obj1": {
number: "123"
},
{
"obj2": {
number: "456"
},
{
"obj2": {
number: "789"
}
];
I have been trying to do this with a push and a for loop but I seem to end up with each object containing all three strings.
Its easy:-
for (var i = 0; i < objects.length; i++) {// start loop for getting values one by one from object array
objects[i].number = strings[i]; // assign string values to object array values
}
Matched object and string share the same array index:
for (var i = 0; i < objects.length; i++) {
objects[i].number = strings[i];
}
Or you could do this using the map function:
var results = objects.map(function (value, index) {
return Object.assign({}, value, { number: strings[index] });
});
The other answers are good I just wanted to give you another way. This way you also do not modify the existing objects array
In case you don't know Object.assign add to the first argument (in our case the empty object {}) all the properties from the other object arguments. You can read more about it here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
Also, you can learn here about the map function: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map

Convert Array of Javascript Objects to single simple array

I have not been able to figure out how to properly accomplish this.
I have a JS array of objects that looks like this:
[{"num":"09599","name":"KCC","id":null},{"num":"000027","name":"Johns","id":null}]
I would like to convert this into a simple, single JS array, without any of the keys, it should look like this:
[
"09599",
"KCC",
"000027",
"Johns" ]
The IDs can be dropped entirely. Any help would be really appreciated.
Simply iterate the original array, pick the interesting keys and accumulate them in another array, like this
var keys = ['num', 'name'],
result = [];
for (var i = 0; i < data.length; i += 1) {
// Get the current object to be processed
var currentObject = data[i];
for (var j = 0; j < keys.length; j += 1) {
// Get the current key to be picked from the object
var currentKey = keys[j];
// Get the value corresponding to the key from the object and
// push it to the array
result.push(currentObject[currentKey]);
}
}
console.log(result);
// [ '09599', 'KCC', '000027', 'Johns' ]
Here, data is the original array in the question. keys is an array of keys which you like to extract from the objects.
If you want to do this purely with functional programming technique, then you can use Array.prototype.reduce, Array.prototype.concat and Array.prototype.map, like this
var keys = ['num', 'name'];
console.log(data.reduce(function (result, currentObject) {
return result.concat(keys.map(function (currentKey) {
return currentObject[currentKey];
}));
}, []));
// [ '09599', 'KCC', '000027', 'Johns' ]
You can use Object.keys() and .forEach() method to iterate through your array of object, and use .map() to build your filtered array.
var array = [{"num":"09599","name":"KCC","id":null},{"num":"000027","name":"Johns","id":null}];
var filtered = array.map(function(elm){
var tmp = [];
//Loop over keys of object elm
Object.keys(elm).forEach(function(value){
//If key not equal to id
value !== 'id'
//Push element to temporary array
? tmp.push(elm[value])
//otherwise, do nothing
: false
});
//return our array
return tmp;
});
//Flat our filtered array
filtered = [].concat.apply([], filtered);
console.log(filtered);
//["09599", "KCC", "000027", "Johns"]
How about using map :
var data = [
{"num":"09599","name":"KCC","id":null}
{"num":"000027","name":"Johns","id":null}
];
var result = data.map(function(obj) {
return [
obj.num,
obj.name,
obj.id
];
});

How do you search object for a property within property?

I have this object:
key = {
spawn:{type:1,img:app.assets.get('assets/spawn.svg')},
wall:{type:2,img:app.assets.get('assets/wall.svg')},
grass:{type:3,img:app.assets.get('assets/grass.svg')},
spike:{type:4,img:app.assets.get('assets/spike.svg')},
ground:{type:5,img:app.assets.get('assets/ground.svg')}
};
And I have an array with only types and I need to add the given image to it, the array looks something like this:
[{type:1,image:null},{type:3,image:null},{type:2,image:null},{type:2,image:null},{type:5,image:null}]
Basically I want to loop the array, find the type in the key object and get the given image and save it into the array.
Is there any simple way to do this?
One thing that stands out here for me is the line
...get the given image and save it into the array
I'm assuming this means the original array. I think a better approach would be to map the appropriate keys and values to a new array but I've assumed, for this example, that it's a requirement.
In an attempt to keep the solution as terse as possible and the request for a lodash solution:
_.each(key, function(prop){
_.each(_.filter(types, { type: prop.type }), function(type) { type.image = prop.img });
});
Given the object of keys and an array of objects like so:
var key = {
spawn:{type:1,img:app.assets.get('assets/spawn.svg')},
wall:{type:2,img:app.assets.get('assets/wall.svg')},
grass:{type:3,img:app.assets.get('assets/grass.svg')},
spike:{type:4,img:app.assets.get('assets/spike.svg')},
ground:{type:5,img:app.assets.get('assets/ground.svg')}
};
var arr = [{type:1,image:null},{type:3,image:null},{type:2,image:null},{type:2,image:null},{type:5,image:null}];
We can first create an array of the properties in the object key to make iterating it simpler.
Then loop over the array arr, and upon each member, check with a some loop which image belongs to the member by its type (some returning on the first true and ending the loop).
You can change the forEach to a map (and assign the returned new array to arr or a new variable) if you want the loop to be without side-effects, and not to mutate the original array.
var keyTypes = Object.keys(key);
arr.forEach(function (item) {
keyTypes.some(function (keyType) {
if (key[keyType].type === item.type) {
item.image = key[keyType].img;
return true;
}
return false;
});
});
The smarter thing would be to change the object of the imagetypes so that you could use the type as the accessing property, or create another object for that (as pointed out in another answer).
I'm not sure if this solution is modern, but it does not use any loops or recursion.
object = {
spawn: {type:1, img:app.assets.get('assets/spawn.svg')},
wall: {type:2, img:app.assets.get('assets/wall.svg')},
grass: {type:3, img:app.assets.get('assets/grass.svg')},
spike: {type:4, img:app.assets.get('assets/spike.svg')},
ground: {type:5, img:app.assets.get('assets/ground.svg')}
};
arr = [
{type:1, image:null},
{type:3, image:null},
{type:2, image:null},
{type:2, image:null},
{type:5, image:null}
];
var typeImages = {};
Object.getOwnPropertyNames(object).forEach(function(value){
typeImages[object[value].type] = object[value].img;
});
arr = arr.map(function(value){
return {
type: value.type,
image: typeImages[value.type]
};
});
var key = {
spawn:{type:1,img:app.assets.get('assets/spawn.svg')},
wall:{type:2,img:app.assets.get('assets/wall.svg')},
grass:{type:3,img:app.assets.get('assets/grass.svg')},
spike:{type:4,img:app.assets.get('assets/spike.svg')},
ground:{type:5,img:app.assets.get('assets/ground.svg')}
};
var typesArray = [{type:1,image:null},{type:3,image:null},{type:2,image:null},{type:2,image:null},{type:5,image:null}];
for(var i = 0, j = typesArray.length; i < j; i++)
{
typesArray[i].image = getKeyObjectFromType(typesArray[i].type).img;
}
function getKeyObjectFromType(type)
{
for(var k in key)
{
if(key[k].type == type)
{
return key[k];
}
}
return {};
}
for (var i = 0; i < typesArray.length; i++) {
for (prop in key) {
if (key[prop].type === typesArray[i].type) {
typesArray[i].image = key[prop].img;
}
}
}
It loops through the array ("typesArray"), and for each array item, it go through all the objects in key looking for the one with the same "type". When it finds it, it takes that key object's "img" and saves into the array.
Using lodash (https://lodash.com/):
var key = {
spawn:{type:1,img:app.assets.get('assets/spawn.svg')},
wall:{type:2,img:app.assets.get('assets/wall.svg')},
grass:{type:3,img:app.assets.get('assets/grass.svg')},
spike:{type:4,img:app.assets.get('assets/spike.svg')},
ground:{type:5,img:app.assets.get('assets/ground.svg')}
};
var initialList = [{type:1,image:null},{type:3,image:null},{type:2,image:null},{type:2,image:null},{type:5,image:null}];
var updatedList = _.transform(initialList, function(result, item) {
item.image = _.find(key, _.matchesProperty('type', item.type)).img;
result.push(item);
});
This will go over every item in the initialList, find the object that matched their type property in key and put it in the image property.
The end result will be in updatedList

Get number of rows of multidimensional JSON variable

I have a PHP function that returns a multiple-level JSON object in the format
var data = {
1 : {
1: { Object },
2: { Object },
...,
...
},
2: {
1: { Object },
2: { Object },
...,
...
}
}
I need to get the length of data to initialize a for loop maximum value. By this, I mean the count of the first level entries.
data[1].length returns 22, and data[2].length returns 23 via the console.log printout. This is expected, but data.length returns undefined.
Is there a better method than
var count = 0;
for (var i=1; i< Number.MAX_VALUE; i++){
if (typeof data[i] != 'undefined')
count = i;
}
How About
Object.keys(data).length
If you can control the JSON format, nested arrays seem a better alternative.
If not, you can run something like
var length = 0;
for (var i in data) {
if (isFinite(i) && i > length)
length = i;
}
You can count the number of entries in a loop, like this:
var length = 0;
for (var key in data) {
if (data.hasOwnProperty(key)) {
length++;
}
}
However, if you have control over the returned data, it would probably be easier to return an array instead of an object because the array will already have the length property you want.
Why not just do this instead of assigning numeric properties? Arrays will have the length property you wish:
var data = [
[
{ Object },
{ Object },
...,
...
],
[
{ Object },
{ Object },
...,
...
]
]

Categories

Resources