Transformation array to nested object - javascript

I try to convert some data into a javascript object. The data looks like this:
data = [["a","a","a","value1"],
["a","a","b","value2"],
["a","b","value3"],
["a","c","a","value4"]]
What I want to get is:
a = {
"a":{
"a":"value1",
"b":"value2"
},
"b":"value3",
"c":{
"a":"value4"
}
}
Since the amount of nested attributes varies I do not know how to do this transformation.

This should be the function you're looking for:
function addItemToObject(dict, path){
if (path.length == 2){
dict[path[0]] = path[1];
} else {
key = path.shift()
if (! dict[key]) {
dict[key] = {};
}
addItemToObject(dict[key], path);
}
return dict;
}
var result = data.reduce(addItemToObject,{});
The function addItemToObject is a recursive function which creates the depth and inserts the value.
This is applied to everything in data using reduce;

Here's a solution using Ramda.js
const data = [
["a","a","a","value1"],
["a","a","b","value2"],
["a","b","value3"],
["a","c","a","value4"]
]
const transformData =
R.pipe(
R.map(R.juxt([R.init, R.last])),
R.reduce(
(obj, [path, value]) =>
R.assocPath(path, value, obj),
{},
),
)
console.log(transformData(data))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>

I don't get your desired solution as there are 4 blocks of data but only 3 properties in the final object.
However, this is how you can iterate through an array and its child arrays:
var data = [["a","a","a","value1"],
["a","a","b","value2"],
["a","b","value3"],
["a","c","a","value4"]];
//Store your results in here
var result = {};
//Iterate each block of data in the initial array
data.forEach(function(block){
//block will refer to an array
//repeat with the child array
block.forEach(function(item){
//item will point to an actual item in the child array
});
});
forEach() will call a provided function on each item within an array.

Related

How to Concatenate Arrays of Objects and return single Array of Arrays?

I recieve 4 arrays from Geoserver. Each of these arrays contain objects holding lat lng data as here geoserver response.
I need to merge these 4 arrays in one single Array and then convert objects inside them into arrays.
This was used to structure some other response from another API:
var routes = e.routes[0].coordinates
var coords = routes.map(function(obj){
return Object.keys(obj).sort().map(function(key){
return obj[key];
})
})
This is routes and
this is coords
and coords is expected result for Geoserver response.
I get my geoserver response. structured as shown in image after I did this:
function goPark(routeLayer){
var finalRoute = routeLayer._layers;
var coordsArray = Object.keys(finalRoute).map(key => {
return finalRoute[key]
});
coordsArray.forEach(function(data){
var xy = data._latlngs;
})
If i proceed with code below I recieve arrays structured as I want, see here, but still separated. I need to merge them somehow in one single array!
var xxy = xy.map(function(obj){
return Object.keys(obj).map(function(key){
return obj[key];
})
})
There is a great npm package for this kinda task that i used once called deepmerge
You can use it to merge one or more arrays or objects into one and control the enumerable properties.
If you need lazy loading of values only when you access it, you can turn the accumulator function into a generator (for performance). There's other things you can do like using promises and a generator to yield values. Though if you aren't seeing any performance issues it's unnecessary.
function accGoPark(reset) {
return accFn(goPark, reset);
}
function accFn(fn, reset) {
const accs = accFn.accs = accFn.accs || {};
const { name } = fn;
accs[name] = !accs[name] || reset ? [] : accs[name];
accs[name] = accs[name].concat( fn() );
return accs[name];
}
You are just setting a variable xy to a reference to your last data._latlngs iterated in your forEach loop, which is why you only get the last one. You should just map coordsArray directly.
xxy = coordsArray.map(function(data){
var obj = data._latlngs;
return Object.keys(obj).map(function(key){
return obj[key];
})
})
Using Object.values, destructuring, and arrow functions to simplify syntax:
xxy = routeLayer.map( ({ _layers: { _latlngs: xy }) => Object.values(xy) );

while pushing the data in to arrays, not added in order

enter image description here
i need to push the data one after another, but here i am getting to add in disorder like last added array in to first.
for (var key in data[tabName + scoreBreakDown]) {
var values = data[tabName + scoreBreakDown][key];
var staticData = values[0];
var obj = [];
obj.push(staticData.CompanyName);
obj.push(staticData.Country_ORIG);
for (var value in values) {
if (addHeader) {
headersArray.push(values[value].AspectName);
weightArray.push(values[value].ScoreWeight);
}
obj.push(values[value].SPESGScore_ORIG);
}
addHeader = false;
dataArray.push(obj);
}
You can use array.map to map through an array and transform it into a new array in order.
In this example, we are just multiplying each value by 3, but the transformation is arbitrary.
let loop = (arr) => {
return arr.map(item => {
return item*3
})
}
console.log(loop([1,2,3,4,5]))
If you want to loop through an object in order this way, you can use Object.keys() this will return an array of the keys in the object.
let loop = (obj) => {
return Object.keys(obj).map(item => {
return `${item}: ${obj[item]}`
})
}
let obj = {
first_name:"John",
last_name:"Doe",
age:23
}
console.log(loop(obj))
So instead of using a for loop and an if statement to check a condition and push the data to the array after each iteration, you can use something Array.filter() to remove entries you don't want to push, and return them in order.
data = [
{header:true, value:"item1"},
{header:false, value:"item2"},
{header:true, value:"item3"},
]
let array = data.filter(item => {return item.header}).map(item => {
return item.value
})
console.log(array)

array.map() is not a function reactjs

I have a function which stores data after splicing from an array.
const removedItemstax = {};
function findAndRemove1(array, property, value) {
array.forEach(function(result, index) {
if(result[property] === value) {
//Remove from array
var removedItem= array.splice(index, 1);
removedItemstax.push(removedItem);
}
});
}
When I try to get map it using below code to get distinct values const tax = removedItemstax.map(d => d.taxId) I'm getting an error that .map() is not a function.
But when I push the array removedItemstax to console I get to see all the elements stored within it.
I get the same error when I pass the array removedItemstax = {} via props after setting a state to it.
Mapping returns undefined, however pushing it directly displaying complete data assigned to the array. I am following the regular method to map.
You can try this way:
const removedItemstax = [];
function findAndRemove1(array, property, value) {
array.forEach(function(result, index) {
if(result[property] === value) {
//Remove from array
var removedItem = array.splice(index, 1);
removedItemstax.push(removedItem);
}
});
}
Instead removedItemstax be a object, him can to be a array
I figured out the reason for getting undefined elements when mapping. This is due to a multidimensional array being stored in attribute const removeItemstax = [].
I'm using the below command to flatten the multidimensional array into a normal array before mapping it.
Here's the syntax:
const removedItemstax1 = [].concat.apply([], removedItemstax);

reactJS adding a object array to and object within an object array

I got a response from a REST call, which returns and array with objects
response.data.steps
For example it looks like this
Now I need to add to each Child of this array an new Object Array.
What could be a smart solution for this problem?
Thanks.
In order to add a new array property to each item, you can simply do:
const steps = response.data.steps.map(step => ({
...step,
newObjectArray: [],
}))
you can usee Array.prototype.map() to do so
let result = response.data.steps.map(element => {
let ret = [element];
return ret;
});
let arr = [{a:1}, {a:2}, {a:3}];
arr = arr.map(element => {
let ret = [element];
return ret;
});
console.log(arr);

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

Categories

Resources