Find combination of nested JSON keys - javascript

I am having some trouble solving this issue without using nested for-loops. I would like to do it using recursion.
Given the following object:
{
"Color": {
"Black": [],
"White": []
},
"Effect": {
"30W": [],
"40W": [],
"60W": []
}
}
The code should compute each combination of Color and Effect and add a number in the list such that the following is produced:
{
"Color": {
"Black": [
1,
2,
3
],
"White": [
4,
5,
6
]
},
"Effect": {
"30W": [
1,
4
],
"40W": [
2,
5
],
"60W": [
3,
6
]
}
}
My attempt is as follows:
const func = (object, entries) => {
for (let prop in object) {
let counter = 0;
const objLength = Object.keys(object[prop]).length;
for (let key in object[prop]) {
console.log(key + counter)
for (let i = 0; i < entries.length / objLength; i++) {
object[prop][key].push(entries[counter]);
counter++;
}
}
}
return object;
}
However, this does not return the desired output. I think it is because of the inner-most for loop condition.

The best way to handle this is to create your JavaScript object and convert it to a string.
// creating your object with attributes. Objects in objects or whatever you
// need
var obj = new Object();
obj.name = "Dale";
obj.age = 30;
obj.married = true;
dataToAdd.forEach(function(item, index) {
item.married = false;
})
// Then convert it to a string using the following code
var jsonString= JSON.stringify(obj);
console.log(jsonString);

I solved the question by considering the space of each attribute key. Then it is just a matter of finding the cartesian, and adding values accordingly:
const cartesian =(...a) => a.reduce((a, b) => a.flatMap(d => b.map(e => [d, e].flat())));
function diy(jsonObj, counter) {
let permObj = []
let keys = Object.keys(jsonObj)
keys.forEach(key => {
permObj.push(Object.keys(jsonObj[key]))
});
permObj = cartesian(...permObj)
for(let i = 0; i < keys.length; i++) {
for(let j = 0; j < permObj.length; j++) {
jsonObj[keys[i]][permObj[j][i]].push(j + counter);
}
}
return jsonObj;
}

Related

convert special array to object [duplicate]

This question already has answers here:
Create objects dynamically out of a dot notation like string
(6 answers)
Closed 1 year ago.
I am trying to convert the following array into an object:
var arr = [
'car.name',
'car.age',
'car.event.id',
'zz.yy.dd.aa',
'aa.yy.zz.dd.kk'
];
So it will look like this:
var targetObject = {
car: {
name: '',
age: '',
event: {
id: ''
}
}
,
zz: {
yy: {
dd: {
aa: ''
}
}
},
aa: {
yy: {
zz: {
dd: {
kk: '',
}
}
}
}
}
This is my code:
targetObject = {}
function arrayToObject(arr){
//iterate through array and split into items
for (var i = 0; i < arr.length; ++i){
var item = arr[i].split(".");
//iterate through item that has just been splitted
for (var u = 0; u < item.length; ++u){
//if item is not in targetobject create new object
if(!(item[0] in targetObject)){
targetObject[item[0]] = {}
} else {
//else go into the object and add the item/property to the existing object
targetObject[item[0]][item[u]] = {}
}
}
}
console.log(targetObject);
}
arrayToObject(arr);
It outputs only in second level and i can't figure out to do it with the several levels. I know the code is oldschool, so I would also really like to know how this can be done easier.
You could use forEach to loop over array and then split with reduce to build nested object.
var arr = [
'car.name',
'car.age',
'car.event.id',
'zz.yy.dd.aa',
'aa.yy.zz.dd.kk'
];
const result = {}
arr.forEach(str => {
str.split('.').reduce((r, e, i, a) => {
return r[e] = (r[e] || (a[i + 1] ? {} : ''))
}, result)
})
console.log(result)
Or with your approach with for loops you just need to keep some reference and update the current nested object, so you could do it like this.
var arr = [
'car.name',
'car.age',
'car.event.id',
'zz.yy.dd.aa',
'aa.yy.zz.dd.kk'
];
const targetObject = {}
let ref = targetObject;
function arrayToObject(arr) {
//iterate through array and split into items
for (var i = 0; i < arr.length; ++i) {
var item = arr[i].split(".");
//iterate through item that has just been splitted
for (var u = 0; u < item.length; ++u) {
const last = u == item.length - 1
const str = item[u]
if (!ref[str]) {
ref[str] = (last ? '' : {})
}
ref = ref[str]
if (last) {
ref = targetObject;
}
}
}
}
arrayToObject(arr);
console.log(targetObject)

Pass data to a function untill array length

So I have a function that takes multiple arrays as arguments but the data I have is already in an array (say mainArr). so mainArr is an array that contains multiple array items that I need to put them in the function arguments.
here's the code:
// NOTE: YOU DON'T NEED TO UNDERSTAND THIS FUNCTION
function getCombinations(...args) {
let r = [], max = args.length - 1;
function helper(arr, i) {
for (let j = 0; j < args[i].length; j++) {
let a = arr.slice(0); // clone arr
a.push(args[i][j].value);
if (i === max) {
r.push(a);
} else {
helper(a, i + 1);
}
}
}
helper([], 0);
return r;
}
I want something like this:
const mainArr = [
{
values: [
{ value: 1 },
{ value: 2 }
]
}, {
values: [
{ value: 2 },
{ value: 1 }
]
}
]
getCombinations(mainArr[0].values, mainArr[1].values)
actually, I want to get the combinations of arrays and the function I made to get the combination, takes multiple arrays as arguments. for example, if I want to get the combination of two arrays, it takes two arrays as two different arguments. but the data I have is inside another array so I just want to strip the arrays from that single array.
Make the parameter of function getCombinations an array.
function getCombinations(args) {
let r = [], max = args.length - 1;
function helper(arr, i) {
for (let j = 0; j < args[i].length; j++) {
let a = arr.slice(0); // clone arr
a.push(args[i][j].value);
if (i === max) {
r.push(a);
} else {
helper(a, i + 1);
}
}
}
helper([], 0);
return r;
}
const mainArr = [
{
values: [
{ value: 1 },
{ value: 2 }
]
}, {
values: [
{ value: 2 },
{ value: 1 }
]
}
]
const x = getCombinations([mainArr[0].values, mainArr[1].values]);
console.log(x);
const list = mainArr.map(node => node.values);
const y = getCombinations(list);
console.log(y);

Merge 2 arrays keeping inner elements array values

I'm trying to merge 2 objects which contains arrays in one of their elements. I don't achieve the disered result when using spread syntax and the first object array is being replaced by the second one. The objects are like the following:
const objectA1 = {
keyA1:'valueA1',
keyArr:[{
arrKeyA01:'arrValueA01',
arrKeyA02:'arrValueA02',
},
{
arrKeyA11:'arrValueA11',
arrKeyA12:'arrValueA12',
}
]
}
const objectB1 = {
keyB1:'valueB1',
keyArr:[{
arrKeyB01:'arrValueB01',
arrKeyB02:'arrValueB02',
},
{
arrKeyB11:'arrValueB11',
arrKeyB12:'arrValueB12',
}
]
}
And I want to get:
const objectRes = {
keyA1:'valueA1',
keyB1:'valueB1',
keyArr:[{
arrKeyA01:'arrValueA01',
arrKeyA02:'arrValueA02',
arrKeyB01:'arrValueB01',
arrKeyB02:'arrValueB02',
},
{
arrKeyA11:'arrValueA11',
arrKeyA12:'arrValueA12',
arrKeyB11:'arrValueB11',
arrKeyB12:'arrValueB12',
}
]
}
What I'm using is
{...objectA1 ,...objectB1}
But as said, the keyArr doesn't keep the objectA1 elements.
How I can merge both objects and keep the array data using spread syntax?
Thanks for any comment/help :)
Create an object and place the first 2 values from A1 and B2 object. Customize the array separately by using reduce
const objectA1 = {
keyA1: 'valueA1',
keyArr: [{
arrKeyA01: 'arrValueA01',
arrKeyA02: 'arrValueA02',
},
{
arrKeyA11: 'arrValueA11',
arrKeyA12: 'arrValueA12',
}
]
}
const objectB1 = {
keyB1: 'valueB1',
keyArr: [{
arrKeyB01: 'arrValueB01',
arrKeyB02: 'arrValueB02',
},
{
arrKeyB11: 'arrValueB11',
arrKeyB12: 'arrValueB12',
}
]
}
const arr = objectA1.keyArr.reduce((acc, x) => {
const res1 = objectB1.keyArr.reduce((acc2, y) => ({...x,...y}), {})
return acc = [...acc, res1];
}, [])
const result = {
keyA1: objectA1.keyA1,
keyB1: objectB1.keyB1,
keyArr: arr
}
console.log(result)
I wanted to share my attemp solving this problem, I take the array and merge it in one using loops:
const objectA1 = {
keyA1:'valueA1',
keyArr:[{
arrKeyA01:'arrValueA01',
arrKeyA02:'arrValueA02',
},
{
arrKeyA11:'arrValueA11',
arrKeyA12:'arrValueA12',
}
]
}
const objectB1 = {
keyB1:'valueB1',
keyArr:[{
arrKeyB01:'arrValueB01',
arrKeyB02:'arrValueB02',
},
{
arrKeyB11:'arrValueB11',
arrKeyB12:'arrValueB12',
}
]
}
objects = [objectA1, objectB1];
let i = 0;
new_array = {};
for(i; i < objects.length; i++){
object = objects[i];
keys = Object.keys(object);
for(j = 0; j < keys.length; j++){
//if property already exists, example keyArr
this_key = keys[j];
console.log(this_key);
if(new_array[this_key] != undefined){
//loop through that property in the object
object[this_key].forEach((object_value, index) => {
//add all properties that previous object did not have
Object.assign(new_array[this_key][index], object_value);
});
}else{
//initialize that value with the first element array
new_array[this_key] = object[this_key];
}
}
}
console.log(objects);
console.log(new_array);

JavaScript: transform a string to json with some rules

I need to write a function which can transform the following data (input string) to a json.
data:
AA,BB
,CC
,,DD
,EE
JSON:
{
"AA": [
{
"BB": []
},
{
"CC": [
{
"DD": []
}
]
},
{
"EE": []
}
]
}
AA, BB, CC ... can any string and the data is input as a string.
I write a part of the function (see the following codes) and have no more good idea.
function str2json(str) {
var lines = str.split("\n");
var arr = new Array();
for (let i = 0; i < lines.length; i++)
{
var objs = lines[i].split(",");
arr.push(objs);
}
for (let i=0; i < arr.length; i++)
{
for (let j=0; j < arr[i].length; j++)
{
if(arr[i][j].length === 0)
{
arr[i][j] = arr[i-1][j];
}
else
{
break;
}
}
}
// TODO
}
I just transform the data into an array then add right data into null, the result is:
AA,BB
AA,CC
AA,CC,EE
AA,FF
Then I thought of using a loop to create an object then use JSON.stringify(object).
How can I continue or redo it?
Thanks!
You could take a helper array for all last levels and pick the result from the first element.
This works because you take after splitting an empty string as flag for taking the last array for inserting a new object.
var data = 'AA,BB\n,CC\n,,DD\n,EE',
result = [],
levels = [result];
data
.split('\n')
.forEach(s => s
.split(',')
.forEach((v, i) => {
if (!v) return;
levels[i].push({ [v]: (levels[i + 1] = []) });
})
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Weird Behavior Pushing Into Array Stored in a JavaScript Object's Value

Inside of the else clause, the commented out line gives the desired result, but the one below it causes { '1': [ 1.3 ], '2': [ 2.1 ] } to become { '1': [ 1.3 ], '2': 2 }. I don't understand why this is happening.
const groupBy = (array, callback) => {
let obj = {}
for (let i = 0; i < array.length; i++) {
let currKey = callback(array[i])
let newVal = array[i]
let currVal = obj[currKey]
if (!currVal) {
obj[currKey] = [newVal]
} else {
// obj[currKey].push(newVal)
obj[currKey] = currVal.push(newVal)
}
}
return obj
}
// Uncomment these to check your work!
var decimals = [1.3, 2.1, 2.4]
var floored = function(num) { return Math.floor(num) }
groupBy(decimals, floored); // expect { 1: [1.3], 2: [2.1, 2.4] }
Array.prototype.push does not return a new array, it returns the length of the array.
const groupBy = (array, callback) => {
// let arrayValues = [] // this isn't used anywhere
let obj = {}
for (let i = 0; i < array.length; i++) {
let currKey = callback(array[i])
let newVal = array[i]
let currVal = obj[currKey]
if (!currVal) {
obj[currKey] = [newVal]
} else {
obj[currKey].push(newVal) // this should work instead
//obj[currKey] = currVal.push(newVal)
}
}
return obj
}
Since arrays are a reference type you just need to push your new item into the array obj[currKey].push(newValue) without setting obj[currKey] again. You're pushing a new value into that array where it lives in memory so no need to re-assign it to anything. You can see how lodash does that here (although you'll have to untangle some helper functions).
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push

Categories

Resources