Convert Array To Nested JSON in Javascript? - javascript

Basically i want to create a tree structure. For example if you have an array of four items ['a', 'b', 'c', 'd'] then i need a JSON from this which should be
{a: {b: {c: {d: 0} } } }
last item of JSON have value of 0 or it can be anything except object.

The conversion steps are straightforward with simple loop:
Reverse the array, so the last becomes the first to convert (and it becomes the inner-most element of JSON).
Iterate through each element, make key-value pair of the object, wrap it repeatedly.
Done
Sample code:
var array = ['a', 'b', 'c', 'd']; // input array
var json = {}; // output object
array.reverse().forEach(function(el){
if (Object.keys(json).length==0){
json[el] = 0;
}
else{
var outer = {};
outer[el] = json;
json = outer;
}
});
Output
{"a": {"b": {"c": {"d": 0} } } }

In an ES5 environment.
var data = ['a', 'b', 'c', 'd'],
jsObject = data.reduceRight(function (acc, datum) {
var val = {};
val[datum] = acc;
return val;
}, 0),
jsonString = JSON.stringify(jsObject);
document.getElementById('out').textContent = jsonString;
<pre id="out"></pre>

Related

Adding an Array Value as a Javascript Object Property

function select(arr, obj) {
var myKeys = Object.keys(obj);
var myValues = Object.values(obj);
var newObj = {};
for(var i=0; i<myKeys.length; i++) {
if(arr[i] === myKeys[i]) {
newObj[myKeys[i]] = myValues[i];
}
}
return newObj;
}
var arr = ['a', 'c', 'e'];
var obj = {
a: 1,
b: 2,
c: 3,
d: 4
};
var output = select(arr, obj);
console.log(output); // --> { a: 1, c: 3 }
/*
If keys are present in the given array, but are not in
the given object, it should ignore them.
It does not modify the passed in object.
*/
I'm having trouble adding an array as an object property. I created a new Object to store the values in, however it only stores the first instance of arr[i]. I'm confused at this point any help?
Do this instead
for(var i=0; i<arr.length; i++) {
if(myKeys[arr[i]] !== undefined) {
newObj[arr[i]] = myValues[i];
}
}
Your code works only if the index of matching keys is exactly the same.
The problem in your code is that it assumes that the ith value in the array must correspond to the ith key of the object, but that order is not guaranteed.
Here is a functional programming style solution, that uses Obect.fromEntries to construct the returned object:
const select = (arr, obj) =>
Object.fromEntries(arr.filter(key => key in obj).map(key => [key, obj[key]]));
var arr = ['a', 'c', 'e'];
var obj = {a: 1,b: 2,c: 3,d: 4};
var output = select(arr, obj);
console.log(output);
I'd use the relatively recently added Object.fromEntries to create an object directly from a map of a filtered set of keys from your object.
function select (arr, obj) {
// get the keys from obj and filter to those present in arr
var keys = Object.keys(obj).filter(key => arr.includes(key));
// create an array of arrays where each inner array has a key and value
var entries = keys.map(key => [key, obj[key]]);
// call fromEntries with that new array.
return Object.fromEntries(entries);
}
var arr = ['a', 'c', 'e'];
var obj = {
a: 1,
b: 2,
c: 3,
d: 4
};
var output = select(arr, obj);
console.log(output); // --> { a: 1, c: 3 }
/*
If keys are present in the given array, but are not in
the given object, it should ignore them.
It does not modify the passed in object.
*/

Given an array of arrays how do I convert this to an object?

Given an array of arrays, how do I convert this to a JavaScript object with the condition that the first element of each array of the internal arrays will be a key of a new JavaScript object, the subsequent element would be the value?
And if there is more than one occurrence of the element in the first position of the internal arrays only create a single key corresponding to this element.
For example:
var arr = [['a', 'b'], ['c', 'd'], ['a', 'e']]
should return:
var obj = {a: ["b", "e"], c: ["d"]}
Here there are 2 occurrences of a within arr therefore only a single key a was created in obj along with c
Using Array.prototype.reduce function, you can accomplish this as follows.
var arr = [['a', 'b'], ['c', 'd'], ['a', 'e']];
const output = arr.reduce((acc, cur) => {
acc[cur[0]] ? acc[cur[0]].push(cur[1]) : acc[cur[0]] = [ cur[1] ];
return acc;
}, {});
console.log(output);
This is an alternative:
var arr = [['a', 'b'], ['c', 'd'], ['a', 'e']]
const obj = {}
arr.forEach(([k, v]) => obj[k] = [...obj[k] ?? [], v])

JavaScript/ES 6: Compare arrays length in an Object

I have an Object containing multiple arrays like this
someObj = {
array1:['a', 'b'],
array2:['a', 'b', 'c'],
array3:['a', 'b', 'c', 'd']
}
Is there any built-in method or property in JS/ES6 which returns the largest array or length of the largest array? Please suggest
You can use Array.prototype.reduce and check the value of accumulator with the array length.
Use Object.values() to get all the values of the array.
var someObj = {
array1:['a', 'b'],
array2:['a', 'b', 'c'],
array3:['a', 'b', 'c', 'd'],
array4:['a', 'b', 'c']
}
var maxLength = Object.values(someObj).reduce((a,e) => { return a > e.length ? a:e.length}, 0);
console.log(maxLength);
You can use Object.values to get all of the values for any object. Here's a neat oneshot which will return the longest list in combination with reduce:
const longestList = Object.values(someObj)
.reduce((longest, list) => list.length > longest.length ? list : longest)
Object.values: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/values
reduce: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
You can simply use a for loop and iterate through it comparing the length of the arrays.
var someObj = {
array1:['a', 'b'],
array2:['a', 'b', 'c'],
array3:['a', 'b', 'c', 'd']
}
var max=0;
for(x in someObj){
someObj[x].length > max ? max=someObj[x].length : max;
}
console.log(max);

How to change an element in for-of loop

How to I change the object in the array with For-of loop?
Following code:
let arr = ['a', 'b', 'c', 'd', 'e'];
for (let v of arr) {
if (v === 'c') {
v = 'f';
break;
}
}
console.log(arr);
I want to find the first letter c and change it to an f, but arr doesn't get changed, probably because it is not referenced ? But shouldn't the v of arr make that the object v is the same as the one in arr ?
Javascript does not create references to simple values such String. To get array referrenced, you need to let array be an array of objects like [{char : 'a'}, {char : 'b'}, ...]. Then in your iterator you can change elements of array through changing of the char property
let arr = [{char: 'a'}, {char :'b'}, ...];
for (let v of arr) {
if (v.char === 'c') {
v.char = 'f';
break;
}
}
v is not a reference to the array element, it's just a variable that is assigned the value that the array iterator yields. If you assign to it, only the variable v changes but not the array.
To do that, you need to explicitly reference the property with its index and assign to it:
let arr = ['a', 'b', 'c', 'd', 'e'];
for (let [i, v] of arr.entries()) {
if (v === 'c') {
arr[i] = 'f';
break;
}
}
console.log(arr); // ['a', 'b', 'f', 'd', 'e']
An iterator does not provide a way to mutate the underlying structure, you need to do it yourself.
As detailed in the MDN spec, let is declaring a new variable from a copy of your array element. So changing the v will not change the value in the array. This is shared by var and const and is simply just javascripts behaviour. When you create a new object, it starts empty.
Your loop is basically saying "For every element in arr, declare a variable holding a copy of it and then if that variable is c, change that copy to f"
Before you change v both, the array and v point to - or in this case have - the same value:
arr[2] -> 'c' <- v
After you change v it has a different value, but you didn't change the array:
arr[2] -> 'c' v -> 'f'
v and arr[2] are only placeholders, but different ones.
The correct answer:
let arr = ['a', 'b', 'c', 'd', 'e'];
let i = 0;
for (let v of arr) {
if (v == 'c') {
arr[i] = 'f';
break;
}
i++;
}
console.log(arr);
:-P

How to get all unique elements in for an array of array but keep max count of duplicates

The question doesn't make much sense but not sure how to word it without an example. If someone can word it better, feel free to edit it.
Let's say I have an array of arrays such as this:
[ ['a', 'a', 'b', 'c'], [], ['d', 'a'], ['b', 'b', 'b', 'e'] ]
I would like the output to be:
['a', 'a', 'b', 'b', 'b', 'c', 'd', 'e']
Not sure if there is an easy way to do this in javascript/jquery/underscore. One way I could think of is to look through each of these arrays and count up the number of times each element shows up and keep track of the maximum amount of times it shows up. Then I can recreate it. But that seems pretty slow considering that my arrays can be very large.
You need to:
Loop over each inner array and count the values
Store each value and its count (if higher than current count) in a counter variable
In the end, convert the value and counts into an array
Following code shows a rough outline of the process. Remember to replace .forEach and for..in with appropriate code:
var input = [['a', 'a', 'b', 'c'], [], ['d', 'a'], ['b', 'b', 'b', 'e']],
inputCount = {};
input.forEach(function(inner) {
var innerCount = {};
inner.forEach(function(value) {
innerCount[value] = innerCount[value] ? innerCount[value] + 1 : 1;
});
var value;
for (value in innerCount) {
inputCount[value] = inputCount[value] ? Math.max(inputCount[value], innerCount[value]) : innerCount[value];
}
});
console.log(inputCount);
// Object {a: 2, b: 3, c: 1, d: 1, e: 1}
After messing around, I found a solution but not sure if I like it enough to use. I would probably use it if I can't think of another one.
I would use underscorejs countBy to get the count of all the elements.
var array = [ ['a', 'a', 'b', 'c'], [], ['d', 'a'], ['b', 'b', 'b', 'e'] ];
var count = _.map(array, function(inner) {
return _.countBy(inner, function(element) {
return element;
});
});
var total = {};
_.each(_.uniq(_.flatten(array)), function(element) {
var max = _.max(count, function(countedElement) {
return countedElement[element];
});
total[element] = max[element];
});
console.log(total); // {a: 2, b: 3, c: 1, d: 1, e: 1}
Then I would recreate the array with that total.
Here is example of simple nested loop approach:
var input = [ ['a', 'a', 'b', 'c'], [], ['d', 'a'], ['b', 'b', 'b', 'e'] ];
var countMap = {};
// iterate outer array
for (i=0; i < input.length; i++) {
// iterate inner array
for (j=0; j < input[i].length; j++) {
// increment map counter
var value = input[i][j];
if (countMap[input[i][j]] === undefined) {
countMap[value] = 1;
} else {
countMap[value]++;
}
}
}
console.log(countMap); // output such as {'a':2, 'b':4, 'c':1, 'd':1, 'e':1}
Not the most efficient solution but it should describe you the process:
var big = [ ['a', 'a', 'b', 'c'], [], ['d', 'a'], ['b', 'b', 'b', 'e'] ];
function map(arr){
var map = {}
for (var i=arr.length-1; i>-1; i--){
if(arr[i] in map) map[arr[i]]++;
else map[arr[i]] = 1;
}
return map;
}
function reduce(matrix){
var arrMap = {};
for (var i=matrix.length-1; i>-1; i--){
var arrRes = map(matrix[i]);
for (var key in arrRes){
if( !arrMap[key] || arrMap[key] < arrRes[key])
arrMap[key] = arrRes[key];
}
}
return arrMap;
}
function calc(matrix){
var res = [],
arrMap = reduce(matrix);
for (var key in arrMap){
while(arrMap[key] > 0 ){
res.push(key);
arrMap[key]--;
}
}
return res;
}
console.log(calc(big));
// Array [ "e", "b", "b", "b", "a", "a", "d", "c" ]

Categories