Simplification of multi level object array in JavaScript - javascript

I have a JavaScript array:
var data = [{abc: "vf",def: [{ a:"1", b:"3"},{a:"2",b:"4"}]}];
I want it to convert to:
[{"abc":"vf","a":"1","b":"3"},{"abc":"vf","a":"2","b":"4"}]
I have written the JavaScript code for it:
Javascript:
var push_apply = Function.apply.bind([].push);
var slice_call = Function.call.bind([].slice);
Object.defineProperty(Array.prototype, "pushArrayMembers", {
value: function() {
for (var i = 0; i < arguments.length; i++) {
var to_add = arguments[i];
for (var n = 0; n < to_add.length; n+=300) {
push_apply(this, slice_call(to_add, n, n+300));
}
}
}
});
var globalResultArr = [];
var data = [{abc: "vf",def: [{ a:"1", b:"3"},{a:"2",b:"4"}]}];
function f(){
for(var i=0;i<data.length;i++){ //Iterate Data Array
var obj = data[i];
var resultArray = [{}];
for (var key in obj) { // Iterate Object in Data Array
if (obj.hasOwnProperty(key)) {
if(Object.prototype.toString.call(obj[key]) === "[object Array]"){
var tempRes = $.extend(true, [], resultArray);
resultArray = [];
for(var k=0;k<tempRes.length;k++){
var tempResObj = tempRes[k];
for(var j=0;j<obj[key].length;j++){ // If it has array, then iterate it as well
var innerObj = obj[key][j]; //Iterate Object in inner array
for(var innerkey in innerObj){
if (innerObj.hasOwnProperty(innerkey)) {
tempResObj[innerkey] = innerObj[innerkey];
}
}
resultArray.push(tempResObj);
}
}
}else{
for(var i=0;i<resultArray.length;i++){
resultArray[i][key] = obj[key];
}
}
}
}
globalResultArr.pushArrayMembers(resultArray);
}
document.getElementById("test").innerHTML = JSON.stringify(globalResultArr);
}
f();
HTML:
<div id="test"></div>
Issue is that browser crashes when item in data array > 10000. How can i make this work? Is there any simpler approach?
JSFiddle

Here's an attempt. It assumes there is only one property in each object that is an array. It them composes an object with the remaining properties and makes a new clone with each value from the array property.
* Works as required now *
var resultArray = [],
len = data.length,
tempObj,
newObj,
targetVal,
targetKey,
composeObj,
tempJson,
key,
i, k;
for(i = 0; i < len; i++) {
tempObj = data[i];
// obj to build up
composeObj = {};
// look at all key/vals in obj in data
for(key in tempObj) {
keyObj = tempObj[key];
// is it an array?
if(Array.isArray(keyObj)) {
// save key/val for array property
targetVal = keyObj;
targetKey = key;
}
else {
// copy non-array properties to empty object
composeObj[key] = keyObj;
}
}
// json-ify the object for cloning
tempJson = JSON.stringify(composeObj);
// compose new object for each val in array property
targetVal.map(function(val) {
// clone object
newObj = JSON.parse(tempJson);
// add array values as object properties
for(k in val) {
newObj[k] = val[k];
}
// add to results
resultArray.push(newObj);
});
}

Related

Loop over each element in Object Arrays [duplicate]

This question already has answers here:
Javascript equivalent of Python's zip function
(24 answers)
Closed 2 years ago.
I've an Object containing data that looks like this,
obj = {
Q1:['val1','val2'],
Q2:['val3','val4','val5'],
Q3:['val8']
}
I was trying to loop over keys and get and first element in each key concate each element in each array, and join them together using , (my object has more keys that this ofc)
So the output should be like
val1,val3,val8
val2,val4,
,val5,
I tried to loop over keys and getting each value but i think i'm missing something in my loop, as i can't change the key if it found element in each object
These are my trials below.
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
for (let i = 0; i < obj[key].length; i++) {
console.log(obj[key][i])//This is always looping on the same key but different element
}
}
}
while i want it to be something close to
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
console.log(obj[key][i])
}
}
My solution uses a deep copy of the object and then a recursive array manipulation via shift():
obj = {
Q1:['val1','val2'],
Q2:['val3','val4','val5'],
Q3:['val8']
}
var resObj = [];
function printByIndex(obj){
var newObj = JSON.parse(JSON.stringify(obj));
printByIndexHelper(newObj, 0);
}
function printByIndexHelper(obj, i){
var flag = false;
resObj[i] = [];
Object.keys(obj).forEach(function(key){
if(obj[key].length > 0){
resObj[i].push(obj[key].shift());
if(obj[key].length > 0){
flag = true;
}
}else{
resObj[i].push(null);
}
});
if(flag){
printByIndexHelper(obj, i+1);
}
}
printByIndex(obj);
console.log(resObj);
Maps over arrays and joins string. Math.max to get full length to iterate over. Uses flatMap to filter out unequal length array values.
obj = {
Q1:['val1','val2'],
Q2:['val3','val4','val5'],
Q3:['val8']
}
const o = Object.values(obj)
const len = Math.max(...o.map(({length})=>length))
console.log(
Array(len).fill().map((x,i)=>o.flatMap(q=>q[i]||[]).join(','))
)
check this same output as u require
obj = {
Q1:['val1','val2'],
Q2:['val3','val4','val5'],
Q3:['val8']
}
var keys = Object.keys(obj);
var stack = [];
var maxLength = getMaxLength(obj);
for(var k = 0; k < 3;k ++) {
var arr = [];
for(var i = 0; i<keys.length;i++) {
const key = keys[i];
const elements = obj[key];
if(k < elements.length) {
arr.push(elements[k]);
}
}
console.log(arr+"\n");
//stack.push(arr);
}
function getMaxLength(jsonObj) {
var max;
var jsonKeys = Object.keys(jsonObj);
for(var key of jsonKeys) {
const arr = jsonObj[key];
if (max == null || arr.length > max) {
max = arr.length;
}
}
return max;
}

How do I assign multiple values to object property with for loop?

I'm trying to assign the name property of obj the [i][0] indices of sampleArr. Console.log(arr[i][0]) outputs "animals", "sopranos", "guitars" with each iteration. However, obj.name = arr[i][0] will only assign obj.name = "guitars".
What explains this behavior, and how could I assign these multiple elements to a single property within a loop?
var sampleArr = [
["animals", ["dogs", "cats", "pigs"]],
["sopranos", ["Tony", "Carmella", "AJ", "Meadow"]],
["guitars", ["Stratocaster", "Telecaster", "Gibson Flying-V"]]
];
function objectifier(arr) {
var obj = {};
for (var i = 0; i < arr.length; i++) {
console.log(arr[i][0])
obj.name = arr[i][0]
}
return obj;
}
how could I assign these multiple elements to a single property within
a loop?
To achieve this you have to keep array in this single property, like this:
function objectifier(arr) {
var obj = {};
obj.name = [];
for (var i = 0; i < arr.length; i++) {
console.log(arr[i][0])
obj.name.push(arr[i][0]);
}
return obj;
}
Replace
obj.name = arr[i][0]
with
obj[i] = {};
obj[i]["name"] = arr[i][0];

Converting Object to sequential array format - javascript?

I am having following object structure
var obj = {"0":"direct","1":"indirect","2":"dir","3":"indir"};
Expected output is:
result = [["direct","indirect"],["indirect","dir"],["dir","indir"]];
What I have tried:
var result = [];
var array = [];
for(var key in obj){
if(array.length <2) {
array.push(obj[key]);
}else{
array =[];
array.push(obj[key-1]);
}
if(array.length == 2){
result.push(array);
}
}
console.log(result);
I am getting the output as follows:
result = [["direct", "indirect"], ["indirect", "indir"]]
If they're all strings that have at least one character, then you can do this:
var obj = {"0":"direct","1":"indirect","2":"dir","3":"indir"};
var result = [];
for (var i = 1; obj[i]; i++) {
result.push([obj[i-1], obj[i]]);
}
It starts at index 1 and pushes the current and previous items in an Array. It continues as long as the values are truthy, so if there's an empty string, it'll stop.
If there could be falsey values that need to be included, then you should count the properties first.
var obj = {"0":"direct","1":"indirect","2":"dir","3":"indir"};
var result = [];
var len = Object.keys(obj).length;
for (var i = 1; i < len; i++) {
result.push([obj[i-1], obj[i]]);
}

rearrange Array according to values order of another Array

I have two arrays like below
var arr = ["x", "y", "z", "a", "b", "c"];
var tgtArr = [{val:"a"}, {val:"b"}]; It does not need to be as lengthy as Array `arr`
This is what I have tried
var dest = new Array(arr.length);
for(var i = 0; i < arr.length; i++){
for(var k = 0; k < tgtArr.length; k++){
dest[i] = dest[i] || [];
if(tgtArr[k].val == arr[i]){
dest[i] = arr[i];
}
}
}
console.log(dest);
My Expected output is (for above tgtArr value)
[{}, {}, {}, {val:"a"}, {val:"b"}, {}];
if tgtArr is empty Array
[{},{},{},{},{},{}]
Here is the fiddle. Any alternative for this, it seems not a good way to me as I am iterating through the entire array everytime.
Short:
var result = arr.map(function(x) {
return tgtArr.some(function(o) { return o.val == x; }) ? {val:x} : {};
});
This is more efficient:
var set = {};
tgtArr.forEach(function(obj, i) {
set[obj.val] = true;
});
var result = arr.map(function(x) {
return x in set ? {val:x} : {};
});
This is the same as Paul's answer, but with a loop instead of map. It collects the keys first based on the val property, then creates a new array either with empty objects if the key isn't in tgtArr, or copies a reference to the object from tgtArr if it is:
function newArray(arr, tgtArr) {
var keys = {},
i = tgtArr.length,
j = arr.length,
newArr = [];
// Get keys
while (i--) keys[tgtArr[i].val] = tgtArr[i];
// Make new array
while (j--) newArr[j] = arr[j] in keys? keys[arr[j]] : {};
return newArr;
}
It should be efficient as it only traverses each array once.
var dest = new Array(arr.length);
for(var i = 0; i < arr.length; i++){
dest[i] = {}
for(var k = 0; k < tgtArr.length; k++){
if(tgtArr[k].val == arr[i]){
dest[i] = tgtArr[k];
}
}
}
console.log(dest);
I like using map rather than loops for this kind of thing (Fiddle):
var result = arr.map(function(x) {
var match = tgtArr.filter(function(y) {
return y.val == x;
});
if (match.length == 1) return match[0];
else return {};
});
This is a possibly inefficient, in that it traverses tgtArr for every item in arr, so O(n*m). If needed, you could fix that by pre-processing tgtArr and converting it to a hash map (Fiddle). This way you've got an O(n+m) algorithm (traverse each array once):
var tgtMap = {};
tgtArr.forEach(function(x) { tgtMap[x.val] = x; })
var result = arr.map(function(x) {
var match = tgtMap[x];
return match || {};
});
var tmp = {};
for (var i = 0; i < tgtArr.length; i++) {
tmp[tgtArr[i].val] = i;
}
var dest = [];
for (var i = 0; i < arr.length; i++) {
var obj= tmp[arr[i]] === undefined ? {} : tgtArr[tmp[arr[i]]];
dest.push(obj);
}
DEMO

Cloning values of keys in Javascript

I have an array (tlist) with keys linked with arrays:
tliste.push({"GROUP104":["321992","322052","321812","314022","0"]});
tliste.push({"GROUP108":["322011","322032","0"]});
tliste.push({"GROUP111":["322020","322021","322040","322041","313060","313072","0"]});
I now need to build a function to take the values of e.g. Group104 and Group111 and clone these into a new array:
newarrray = ["321992","322052","321812","314022","0","322020","322021","322040","322041","313060","313072","0"]
Preferably the new array should be ordered and the "0" should be removed - but that is of lower importance.
Let the groups to be extracted be grp[].
You can do something like this -
// Extract groups in grp[] from origArray[]
var extractGrps = function(grps, origArray) {
var result = [];
for(var i =0; i<grps.length; i+=1) {
var indxInOrigArray = indexOfObjectWithKey(origArray, grps[i]);
if(indxInOrigArray > 0) {
var arrLocal = origArray[indxInOrigArray].grps[i];
for(var j=0; j<arrLocal.length;j+=1)
result.push(arrLocal[j]);
}
}
return result;
}
//find Index of object in arr whose key matches the given input key
var indexOfObjectWithKey = function(arr, key) {
for(var i=0; i<arr.length; i+=1) {
if(arr[i].key) {
return i;
}
}
return -1;
}

Categories