flatten array and put child array into an array of object - javascript

I struggled with a problem for more than an hour, how can I turn this nested array
[
[
{
"name": "1",
}
],
[
{
"name": "a",
},
{
"name": "b",
}
]
]
into this:
[
{
name: '1',
},
{
id: 'a-b',
grouped: [
{
name: 'a',
},
{
name: 'b',
},
],
},
]
I don't mind using lodash. Not sure should I flatten it before anything else would make things easier.

You could use map() to form the id and grab the parts needed to reconstruct the new array.
const data = [
[{
"name": "1",
}],
[{
"name": "a",
},
{
"name": "b",
}
]
];
const result = [
...data[0],
{
id: data[1].map(r => r.name).join("-"),
grouped: data[1]
}
];
console.log(result);

to flatten the array is a good start. That will remove the superfluous dimension from the rawArray:
const newArray = array.flat()
Now you have an array with three simple objects. The first will remain unchanged. The second element of your finalArray needs to be an object, so let's create it:
const obj = {}
the obj has two keys: id and grouped. The property of id is a string that we can create like this:
obj.id = newArray[1].name + "-" + newArray[2].name
the property of grouped remains the same:
obj.grouped = array[1]
so the finalArray is now straight forward:
const finalArray = [ newArray[0], obj ]
Put it all together in a function:
const rawArray1 = [
[
{
"name": "1a",
}
],
[
{
"name": "a",
},
{
"name": "b",
}
]
]
const rawArray2 = [
[
{
"name": "1b",
}
],
[
{
"name": "aa",
},
{
"name": "bb",
}
]
]
transformArray( rawArray1 )
transformArray( rawArray2 )
function transformArray( array ){
const newArray = array.flat()
const obj = {}
obj.id = newArray[1].name + "-" + newArray[2].name
obj.grouped = array[1]
const finalArray = [ newArray[0], obj ]
console.log(finalArray)
return finalArray
}

I managed to solve it using simple forEach, push, and flat. It's more simple than I thought, I was confused and stuck with map and reduce.
let result = [];
[
[{
"name": "1",
}],
[{
"name": "a",
},
{
"name": "b",
}
]
].forEach((val) => {
const [{
name
}] = val
if (val.length === 1) {
result.push({
name,
})
} else if (val.length > 1) {
result.push({
id: val.map(val2 => val2.name).join('-'),
grouped: val
})
}
})
console.log(result.flat())

const array1 = [
[{ name: "1" }],
[
{ name: "a" },
{ name: "b" }
]
]
const array2 = [
[{ name: "2" }],
[
{ name: "aa" },
{ name: "bb" },
{ name: "cc" }
]
]
transformArray( array1 )
transformArray( array2 )
function transformArray( array ){
const result = []
// destructure first array element for the first object:
const [ nameObj ] = array[0]
result.push( nameObj )
// map each object of the second array element into an
// an array of names, and then join the names together:
const dataObj = {}
dataObj.id = array[1].map(obj => obj.name).join('-')
dataObj.grouped = array[1]
result.push( dataObj )
console.log( result )
return result
}

Related

How can I iterate over an array(filter)?

I have this JSON structure:
const arr = [
{
id: "TaskStatuses",
rows: [
{id: "1", name: "Success"},
{id: "2", name: "Error"},
]
},
{
id: "Objects",
rows: [
{id: "1", name: "Object1"},
{id: "2", name: "Object2"},
]
},
{
id: "Groups",
rows: [
{id: "1", name: "Group1"},
{id: "2", name: "Group2"},
]
},
]
I need to create array with some condition. If my condition correctly I will push elements arr.rows.
Finally i want to get this structure:
[
{
Objects: "Object1",
Groups: "Group1"
},
{
Objects: "Object2",
Groups: "Group2"
}
]
I try to do like this
let sites = []
for (let el in arr) {
if (arr.id == "Objects") {
for (let item of el.rows) {
sites.push({Objects: item.name})
}
}
if (arr.id == "Groups") {
for (let item of el.rows) {
sites.push({Groups: item.name})
}
}
Based on comments and your mentioned expected final object array,
I modified your logic a bit to match the expected output.
My approach uses extra space, but o(nlogn) time (not sure if this is most efficient). Hope this code helps.
let firstArr = [], secondArr = [];
arr.forEach((d, i) => {
if (d.id === "Objects") {
firstArr.push(...d.rows);
}
if (d.id === "Groups") {
secondArr.push(...d.rows);
}
});
//console.log(firstArr, secondArr);
//sorting, if necessary based on id of each arr[i].rows
firstArr.sort(function (a, b) {
return a.id - b.id || a.name.localeCompare(b.name);
});
//sorting, if necessary based on id of each arr[i].rows
secondArr.sort(function (a, b) {
return a.id - b.id || a.name.localeCompare(b.name);
});
let index = 0,
size = Math.min(firstArr.length, secondArr.length);
let finalArr = [];
for (index; index < size; index++) {
if (firstArr[index].id === secondArr[index].id) {
finalArr.push({
Objects: firstArr[index].name,
Groups: secondArr[index].name,
});
}
}
//console.log(finalArr); ////this is your final Array.
Instead of building building an array, building an object would simplify things a lot. You can use the id as key for each object so you can easily find the object you want to attach properties to.
The snippet bellow loops through the different "columns". If the column matches the criteria (being either "Objects" or "Groups"), we'll loop through the rows of the column and attach the properties to the resulting object.
const arr = [{
id: "TaskStatuses",
rows: [
{id: "1", name: "Success"},
{id: "2", name: "Error"},
]
}, {
id: "Objects",
rows: [
{id: "1", name: "Object1"},
{id: "2", name: "Object2"},
]
}, {
id: "Groups",
rows: [
{id: "1", name: "Group1"},
{id: "2", name: "Group2"},
]
}];
const sites = {};
const whitelist = new Set(["Objects", "Groups"]);;
for (const column of arr) {
if (!whitelist.has(column.id)) continue;
for (const row of column.rows) {
sites[row.id] ||= {};
sites[row.id][column.id] = row.name;
}
}
console.log(sites);

Mege multiple array object into single array object based on key

I have an array of objects of the structure coming from server response of iterated array object like as sample
var arrObj1 = [
{"id":"1","value":21, "value1":13},
{"id":"2","value":21, "value1":13 },
......n
];
var arrObj2 = [
{"id":"1","value3":21, "value14":13},
{"id":"2","value3":21, "value4":13 },
......n
];
var arrObj3 = [
{"id":"1","value5":21, "value6":13},
{"id":"2","value5":21, "value6":13 },
......n
];
But now I want to append the array values inot single new array according to key following structure of as iterated values of above array Expected Output:
var finalObj = [
{
"id" : 1
"value" : 21,
"value1" : 13,
"value3" : 21,
"value4" : 13,
"value5" : 21,
"value6" : 13,
},
{
"id" : 2
"value" : 21,
"value1" : 13,
"value3" : 21,
"value4" : 13,
"value5" : 21,
"value6" : 13,
},
.....n
];
You can use reduce for concated arrays
const arrObj1 = [
{ id: '1', value: 21, value1: 13 },
{ id: '2', value: 21, value1: 13 },
];
const arrObj2 = [
{ id: '1', value3: 21, value14: 13 },
{ id: '2', value3: 21, value4: 13 },
];
const arrObj3 = [
{ id: '1', value5: 21, value6: 13 },
{ id: '2', value5: 21, value6: 13 },
];
const result = [...arrObj1, ...arrObj2, ...arrObj3].reduce(
(acc, { id, ...rest }) => ({ ...acc, [id]: acc[id] ? { ...acc[id], ...rest } : { ...rest } }),
{},
);
console.log(Object.entries(result).map(([id, data]) => ({ id, ...data })));
Push you arrays to a new array (you have to have your sub arrays in other list to loop through them) and then use flat, after that group your object according to the id property
var arrObj1 = [{
"id": "1",
"value": 21,
"value1": 13
},
{
"id": "2",
"value": 21,
"value1": 13
},
];
var arrObj2 = [{
"id": "1",
"value3": 21,
"value14": 13
},
{
"id": "2",
"value3": 21,
"value4": 13
},
];
var arrObj3 = [{
"id": "1",
"value5": 21,
"value6": 13
},
{
"id": "2",
"value5": 21,
"value6": 13
},
];
const input = [];
input.push(arrObj2, arrObj3);
const preResult = input.flat();
result = preResult.reduce((acc, x) => {
const index = acc.findIndex(y => y.id === x.id)
if (index >= 0) {
acc[index] = {
...acc[index],
...x
}
} else {
acc.push(x)
}
return acc;
}, arrObj1)
console.log(result)
You can iterate over array-length and push here for every entry 1 entry to the result. For getting this entry take a new object with the id and iterate over all (3 or perhaps more) arrays. For every array take the i-th entry and push for every key an entry with key:value (except for the key id itself).
Remark: You can use as much arrays you want and every object could contain as much value-prperties as you need. The only restriction is that every array has the same count of objects.
var arrObj1 = [
{"id":"1","value":21, "value1":13},
{"id":"2","value":21, "value1":13 }
];
var arrObj2 = [
{"id":"1","value3":21, "value4":13},
{"id":"2","value3":21, "value4":13 }
];
var arrObj3 = [
{"id":"1","value5":21, "value6":13},
{"id":"2","value5":21, "value6":13 }
];
let result =[];
let arrayAll = [arrObj1, arrObj2, arrObj3];
for (let i=0; i<arrayAll[0].length; i++) {
let obj = arrayAll[0][i];
let res = { id: obj.id};
for (let j=0; j<arrayAll.length; j++) {
let obj = arrayAll[j][i];
Object.keys(obj).forEach(key => {
if (key!='id') res[key] = obj[key];
})
}
result.push(res);
}
console.log(result);
Since you are using id to merge multiple objects, Map is one of the good option to merge.
let arrObj1 = [
{"id":"1","value":21, "value1":13},
{"id":"2","value":21, "value1":13 },
];
let arrObj2 = [
{"id":"1","value3":21, "value14":13},
{"id":"2","value3":21, "value4":13 },
];
let arrObj3 = [
{"id":"1","value5":21, "value6":13},
{"id":"2","value5":21, "value6":13 },
];
let mergedArray = [...arrObj1,...arrObj2,...arrObj3].reduce((acc,curr) =>{
if(acc.has(curr.id)){
acc.set(curr.id, {...acc.get(curr.id),...curr});
}else{
acc.set(curr.id,curr);
}
return acc;
},new Map())
console.log(Array.from(mergedArray,x=>x[1]));

How to add two or nth different list items with order into a new list?

The problem is how can I add two or n different list items into the order?
Then add them into a new list?
Anyone know is there a faster way to achieve this?
Thanks.
let resultList = [];
const list = [
{
"item": "aaa"
},
{
"item": "ddd"
},
];
const list2 = [
{
"item": "bbb"
},
{
"item": "ccc"
}
];
const list3 = [
{
"item": "xxx"
},
{
"item": "yyy"
}
];
// expected
resultList = [
{
"item": "aaa"
},
{
"item": "bbb"
},
{
"item": "xxx"
},
{
"item": "ddd"
},
{
"item": "ccc"
},
{
"item": "yyy"
},
]
If you can support new JavaScript features such as .flatMap(), you can map each object in list to an array containing the current object along with it's associated object from list2 like so:
const list = [{ "item": "aaa" }, { "item": "ddd" }];
const list2 = [ { "item": "bbb" }, { "item": "ccc" } ];
const res = list.flatMap((o, i) => [o, list2[i]]);
console.log(res);
This can be generalized for multiple lists:
const list = [{ "item": "aaa" }, { "item": "ddd" }];
const list2 = [ { "item": "bbb" }, { "item": "ccc" } ];
const list3 = [ { "item": "xxx" }, { "item": "yyy" } ];
const arr = [list, list2, list3];
const res = arr[0].flatMap((_, i) => arr.map(a => a[i]));
console.log(res);
const list = [
{
"item": "aaa"
},
{
"item": "ddd"
},
];
const list2 = [
{
"item": "bbb"
},
{
"item": "ccc"
}
];
var children = list.concat(list2);
children=children.sort(function(a, b) {
var x = a.item.toLowerCase();
var y = b.item.toLowerCase();
return x < y ? -1 : x > y ? 1 : 0;
})
console.log(children);
You can loop over first array and take the respective index value from other array as well and then push
const list = [{"item": "aaa"},{"item": "ddd"}];
const list2 = [{"item": "bbb"},{"item": "ccc"}];
let final = list.reduce((op, inp, index) => {
op.push(inp, list2[index])
return op
}, [])
console.log(final)
What if i have n list, you can create an array of n-1 list list ( except the first array ). loop over the first array and get to push value from each list loop over remaining and get value at particular index.
const list = [{"item": "aaa"},{"item": "ddd"}];
const list2 = [{"item": "bbb"},{"item": "ccc"}];
const list3 = [{"item": "eee"},{"item": "fff"}];
const list4 = [{"item": "ggg"},{"item": "hhh"}];
const remaining = [list2,list3,list4]
let final = list.reduce((op, inp, index) => {
op.push(inp, ...remaining.map(v=> v[index]))
return op
}, [])
console.log(final)

How do I "flatten" an object into an array of arrays

I have this object:
{
"value": "face",
"next": [
{
"value": "tace",
"next": [
{
"value": "tale",
"next": [
{
"value": "talk",
"next": []
}
]
},
{
"value": "tack",
"next": [
{
"value": "talk",
"next": []
}
]
}
]
},
{
"value": "fack",
"next": [
{
"value": "tack",
"next": [
{
"value": "talk",
"next": []
}
]
},
{
"value": "falk",
"next": [
{
"value": "talk",
"next": []
}
]
}
]
}
]
}
What is the best way to iterate over it and create this array of arrays:
[
["face", "tace", "tale", "talk"],
["face", "tace", "tack", "talk"],
["face", "fack", "tack", "talk"],
["face" ,"fack", "falk", "talk"]
]
I basically want to "flatten" the object into the array format by traversing down each branch of the object and producing an array of strings for each branch.
You can do this by creating recursive function using reduce method, that will store previous values and when there is no elements in next property it will current copy push to result array.
const data = {"value":"face","next":[{"value":"tace","next":[{"value":"tale","next":[{"value":"talk","next":[]}]},{"value":"tack","next":[{"value":"talk","next":[]}]}]},{"value":"fack","next":[{"value":"tack","next":[{"value":"talk","next":[]}]},{"value":"falk","next":[{"value":"talk","next":[]}]}]}]}
const flatten = (obj, prev = []) => {
const next = prev.concat(obj.value)
return obj.next.reduce((r, e) => {
if(e.next.length) r.push(...flatten(e, next))
else r.push(next.slice().concat(e.value));
return r;
}, [])
}
const result = flatten(data);
console.log(result);
You can use recursion with Array.forEach() to iterate the next property, and add the previous items. When next is empty, take everything, flatten, and push to the result:
const flatAll = (data) => {
const result = [];
const fn = ({ value, next }, prev = []) => {
if(next.length) next.forEach(o => fn(o, [prev, value]));
else result.push([prev, value].flat(Infinity));
};
fn(data);
return result;
}
const data = {"value":"face","next":[{"value":"tace","next":[{"value":"tale","next":[{"value":"talk","next":[]}]},{"value":"tack","next":[{"value":"talk","next":[]}]}]},{"value":"fack","next":[{"value":"tack","next":[{"value":"talk","next":[]}]},{"value":"falk","next":[{"value":"talk","next":[]}]}]}]};
const result = flatAll(data);
console.log(result);
You could use an independent recursive function and collect the last item and build an arrayof the given values for every level.
const
flat = (value, next) => next
.reduce((r, { value, next }) => {
if (next.length) r.push(...flat(value, next));
else r.push([value]);
return r;
}, [])
.map(q => [value, ...q]);
var data = { value: "face", next: [{ value: "tace", next: [{ value: "tale", next: [{ value: "talk", next: [] }] }, { value: "tack", next: [{ value: "talk", next: [] }] }] }, { value: "fack", next: [{ value: "tack", next: [{ value: "talk", next: [] }] }, { value: "falk", next: [{ value: "talk", next: [] }] }] }] },
result = flat(data.value, data.next);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Parse json from JavaScript and create new one

[
{“id”:”idtest1",”name”:”aaa"},
{“id”:”idlest2”,”name”:”bbb"},
{“id”:”idlest3","name”:"ccc"},
{“id”:”idtest4","name”:"ddd”},
… ]
I want to get only the name from these arrays. And I want to create a new array using name. The value of name becomes a key and adds a static string to the value.
The static value is increased by one. What should I do?
{
“aaa" : [
"static01value", "static01value", "static01value"
],
“bbb" : [
"static02value", "static02value", "static02value"
],
…..
}
let list = [
{"id":"idtest1","name":"aaa"},
{"id":"idlest2","name":"bbb"},
{"id":"idlest3","name":"ccc"},
{"id":"idtest4","name":"ddd"},
]
let result = list.reduce((acc, {name}, i) => {
acc[name] = Array.from({ length: 3 }, () => `static0${i}value`);
return acc;
}, {});
console.log(result)
You can use reduce method and use Array.from method which
take a length for the array and a callback function which you can use
to modify that array
This is the snippet of what the code should look like, given that the static value is a bit vague:
var array = [
{ id: "idtest1", name: "aaa" },
{ id: "idlest2", name: "bbb" },
{ id: "idlest3", name: "ccc" },
{ id: "idtest4", name: "ddd" }
];
var arrName = array.map(a => a.name),
newArray = [];
arrName.forEach((a, idx) => {
var newObject = {}
newObject[a] = [];
//not quite sure what your static value is, in your example you have 3 static value
for (var i = 0; i < 3; i++) {
newObject[a].push('static value' + idx);
}
newArray.push(newObject);
});
console.log(newArray);
Please try below.
var array = [
{ id: "idtest1", name: "aaa" },
{ id: "idlest2", name: "bbb" },
{ id: "idlest3", name: "ccc" },
{ id: "idtest4", name: "ddd" }
];
const result = {};
array.forEach((item, staticIndex) => {
const staticArray = []
// add static value to array
staticArray.push('staticValue');
result[item.name] = staticArray
})
console.log('Result array is ', result);
Just try to parse your Json using es6 methods.
const array = [
{ id: "idtest1", name: "aaa" },
{ id: "idlest2", name: "bbb" },
{ id: "idlest3", name: "ccc" },
{ id: "idtest4", name: "ddd" }
];
const your_static_content = 'your_static_content'
const output = array.reduce((obj, item) => {
obj[item.name] = obj[item.name] || [];
obj[item.name].push(your_static_content);
return obj;
}, Object.create(null));
console.log(output)
const data = [
{ "id": "idtest1", "name": "aaa" },
{ "id": "idtest2", "name": "bbb" },
{ "id": "idtest3", "name": "ccc" },
{ "id": "idtest4", "name": "ddd" }
]
const getStaticValue = index => `static0${1 + index}value`
const result = data.reduce((result, {name}, index) => ({
...result,
[name]: Array.from({length:3}, getStaticValue)
}), {})
console.log(result)

Categories