Related
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
}
Im trying to parse list of list to json object.I need the following output but my logic is not correct to get the actual output but instead getting im appending the key/value to the array
Input (Array):
var arraysample =
[
[
["firstName", "Vasanth"],
["lastName", "Raja"],
["age", 24],
["role", "JSWizard"]
],
[
["firstName", "Sri"],
["lastName", "Devi"],
["age", 28],
["role", "Coder"]
]
];
Expected OUtput
[
{firstName: “Vasanth”, lastName: “Raja”, age: 24, role: “JSWizard”},
{firstName: “Sri”, lastName: “Devi”, age: 28, role: “Coder”}
]
My output:
[
[ 'firstName', 'Vasanth' ],
[ 'lastName', 'Raja' ],
[ 'age', 24 ],
[ 'role', 'JSWizard' ],
firstName: 'Vasanth',
lastName: 'Raja',
age: 24,
role: 'JSWizard'
],
[
[ 'firstName', 'Sri' ],
[ 'lastName', 'Devi' ],
[ 'age', 28 ],
[ 'role', 'Coder' ],
firstName: 'Sri',
lastName: 'Devi',
age: 28,
role: 'Coder'
]
]
MY Logic:
for(var i=0;i<arraysample.length;i++)
{
for(var j=0;j<arraysample[i].length;j++)
{
arraysample[i][arraysample[i][j][0]]=arraysample[i][j][1];
}
}
You can use Object.fromEntries() with Array.prototype.map():
var arraysample = [
[
["firstName", "Vasanth"],
["lastName", "Raja"],
["age", 24],
["role", "JSWizard"]
],
[
["firstName", "Sri"],
["lastName", "Devi"],
["age", 28],
["role", "Coder"]
]
];
var result = arraysample.map(Object.fromEntries);
console.log(result);
var result = [];
for(var i=0;i<arraysample.length;i++)
{
result[i] = {};
for(var j=0;j<arraysample[i].length;j++)
{
result[i][arraysample[i][j][0]]=arraysample[i][j][1];
}
}
A small Changes in your code.
let finalArray = []
let newArr = []
for (var i = 0; i < arraysample.length; i++) {
for (var j = 0; j < arraysample[i].length; j++) {
newArr[arraysample[i][j][0]] = arraysample[i][j][1]
}
finalArray.push(newArr)
}
console.log(finalArray)
But #MrGeek answer is more acceptable
console.log(
//take your array and read each element in it
arraysample.map((array) => {
let rObj = {};
//create an empty object to put your key name and value
rObj[array[0][0]] = array[0][1];
//rObj[name] = value
rObj[array[1][0]] = array[1][1];
rObj[array[2][0]] = array[2][1];
rObj[array[3][0]] = array[3][1];
return rObj;
})
);
I have similiary problem like here: JavaScript: Find all parents for element in tree recursive
But I don't find path by name but by direct path.
const path = ["name1", "name4", "name5"];
const data = [
{
'name': 'name1',
'tree': [
{'name': 'name2'},
{'name': 'name3'},
{
'name': 'name4',
'tree': [
{'name': 'name5'},
{'name': 'name6'}
]
},
{'name': 'name7'}
]
},
{
'name': 'name8',
'tree': [
{'name': 'name9'}
]
}
];
It returns every possible path or nothing.
When path is too short, it returns nothing.
When path is too long, it returns nothing.
Thanks for help!
Examples of desired output:
const path = ["name1", "name4", "name5"];
findAPath(data, path)
Returns: ["name1", "name4", "name5"]
const path = ["name1", "name7", "name5"];
findAPath(data, path)
Returns []
const path = ["name1", "name4", "name5", "name5"];
findAPath(data, path)
Returns []
My trying:
let index = 0;
function find(data, index) {
let index = index;
data.some((o) => {
if(o.name == path[index]) {
index++;
find(o.tree, index);
}
});
// I don't know what return here.
// I need to probably return path where I am.
return <>;
}
using Array.prototype.flatMap
Here's a functional solution using a mutual recursion technique -
const None =
Symbol ()
const findPath = (tree = [], names = [], r = []) =>
tree.length && names.length // base: and
? tree.flatMap(branch => findPath1(branch, names, r))
: tree.length || names.length // inductive: xor
? []
: [ r ] // inductive: nor // inductive: nor
const findPath1 = ({ name = "", tree = [] } = {}, [ q = None, ...more ] = [], r = []) =>
name === "" && q === None // base: and
? [ r ]
: name === "" || q === None || name !== q // inductive: xor
? []
: findPath(tree, more, [ ...r, q ]) // inductive: nor
findPath(data, ["name1", "name4", "name5"])
// => [ [ "name1", "name4", "name5" ] ]
NB if your data contains multiple paths to the input values, all paths will be returned -
const data = [
{
'name': 'name1', // name1
'tree': [
{'name': 'name2'},
{'name': 'name3'},
{
'name': 'name4', // name1->name4
'tree': [
{'name': 'name5'}, // name1->name4->name5
{'name': 'name6'}
]
},
{
'name': 'name4', // name1->name4
'tree': [
{'name': 'name5'}, // name1->name4->name5
{'name': 'name6'}
]
},
{'name': 'name7'}
]
},
{
'name': 'name8',
'tree': [
{'name': 'name9'}
]
}
]
Just like you asked, it returns every possible path, or nothing -
findPath(data, ["name1", "name4", "name5"])
// => [ [ "name1", "name4", "name5" ],
// [ "name1", "name4", "name5" ] ]
findPath(data, [ "name1", "name7" ])
// => [ [ "name1", "name7" ] ]
findPath(data, [ "name1", "name9" ])
// => []
When a path is too short or too long, it will return nothing -
findPath(data, [ "name1", "name4" ])
// => []
findPath(data, [ "name1", "name4", "name5", "name6" ])
// => []
Expand the snippet below to verify the results in your own browser -
const None =
Symbol ()
const findPath = (tree = [], names = [], r = []) =>
tree.length && names.length
? tree.flatMap(branch => findPath1(branch, names, r))
: tree.length || names.length
? []
: [ r ]
const findPath1 = ({ name = "", tree = [] } = {}, [ q = None, ...more ] = [], r = []) =>
name === "" && q === None
? [ r ]
: name === "" || q === None || name !== q
? []
: findPath(tree, more, [ ...r, q ])
const data = [
{
'name': 'name1',
'tree': [
{'name': 'name2'},
{'name': 'name3'},
{
'name': 'name4',
'tree': [
{'name': 'name5'},
{'name': 'name6'}
]
},
{'name': 'name7'}
]
},
{
'name': 'name8',
'tree': [
{'name': 'name9'}
]
}
]
console.log(findPath(data, ["name1", "name4", "name5"]))
// [ [ "name1", "name4", "name5" ] ]
console.log(findPath(data, [ "name1", "name7" ]))
// [ [ "name1", "name7" ] ]
console.log(findPath(data, [ "name1", "name9" ]))
// []
using Generators
Here's an alternative implementation using generators -
const None =
Symbol ()
const findPath = function* (tree = [], names = [], r = [])
{ if (tree.length && names.length) // base: and
for (const branch of tree)
yield* findPath1(branch, names, r)
else if (tree.length || names.length) // inductive: xor
return
else // inductive: nor
yield r
}
const findPath1 = function* ({ name = "", tree = [] } = {}, [ q = None, ...more ] = [], r = [])
{ if (name === "" && q === None) // base: and
yield r
else if (name === "" || q === None || name !== q) // inductive: xor
return
else // inductive: nor
yield* findPath(tree, more, [ ...r, q ])
}
It has the exact same output as above, only to coerce the iterable generator into an array, we use Array.from -
Array.from(findPath(data, ["name1", "name4", "name5"]))
// => [ [ "name1", "name4", "name5" ] ]
Array.from(findPath(data, [ "name1", "name7" ]))
// => [ [ "name1", "name7" ] ]
Array.from(findPath(data, [ "name1", "name9" ]))
// => []
Expand the snippet below to verify the results in your own browser -
const None =
Symbol ()
const findPath = function* (tree = [], names = [], r = [])
{ if (tree.length && names.length)
for (const branch of tree)
yield* findPath1(branch, names, r)
else if (tree.length || names.length)
return
else
yield r
}
const findPath1 = function* ({ name = "", tree = [] } = {}, [ q = None, ...more ] = [], r = [])
{ if (name === "" && q === None)
yield r
else if (name === "" || q === None || name !== q)
return
else
yield* findPath(tree, more, [ ...r, q ])
}
const data = [
{
'name': 'name1',
'tree': [
{'name': 'name2'},
{'name': 'name3'},
{
'name': 'name4',
'tree': [
{'name': 'name5'},
{'name': 'name6'}
]
},
{'name': 'name7'}
]
},
{
'name': 'name8',
'tree': [
{'name': 'name9'}
]
}
]
console.log(Array.from(findPath(data, ["name1", "name4", "name5"])))
// [ [ "name1", "name4", "name5" ] ]
console.log(Array.from(findPath(data, [ "name1", "name7" ])))
// [ [ "name1", "name7" ] ]
console.log(Array.from(findPath(data, [ "name1", "name9" ])))
// []
how they're the same; how they're not
Note the similarity between the two implementations and how the result is formed. Both use mutual recursion. The functional solution uses expressions whereas the generator solution uses statements. The generator implementation extends a distinct advantage where by we can chose to stop or continue iteration ("finding") whenever we want.
For example, imagine an input where there are ten (10) unique paths for the given input. Perhaps we want to just return the first match,
const findFirst = (tree = [], names = []) =>
{ for (const path of findPath(tree, names))
return path
}
Or get the first three (3) matches -
const findFirst3 = (tree = [], names = []) =>
{ const r = []
for (const path of findPath(tree, names))
if (r.length < 3)
r.push(path)
return r
}
Or get the first N -
const findFirstN = (tree = [], names = [], n = 0) =>
{ const r = []
for (const path of findPath(tree, names))
if (r.length < n)
r.push(path)
return r
}
Generators are flexible like this. By contrast, the flatMap implementation is eager and always returns all results.
Having input like the below:
[
{
gameId: id_0,
groups: [1]
},
{
gameId: id_1,
groups: [2]
},
{
gameId: id_2,
groups: [1, 2]
},
{
gameId: id_3,
groups: [3]
}
]
I would like my reduce to result in an array of objects like:
[
{
group: 1,
data: [
id_0, id_2 // gameId
]
},
{
group: 2,
data: [
id_1, id_2
]
},
{
group: 3,
data: [
id_3
]
}
]
I was able to partially solve this by utilising array indexes.
The code I have currently is:
groupByArr = parameter => data => data.reduce((acc, curr) => {
curr[parameter].forEach(key => {
if (acc[key]) {
acc[key].push(curr)
} else {
acc[key] = [curr]
}
})
return acc
}, [])
which produces an array of arrays where main array index is the group id:
[
empty,
1: [
id_0, id_2
],
2: [
id_1, id_2
],
3: [
id_3
]
]
You can use Array.prototype.reduce() combined with Array.prototype.forEach() and Array.prototype.push() to return an Object and finally get the values with Object.values()
Code:
const data = [{gameId: 'id_0',groups: [1]},{gameId: 'id_1',groups: [2]},{gameId: 'id_2',groups: [1, 2]},{gameId: 'id_3',groups: [3]}]
const result = Object.values(data.reduce((acc, {gameId, groups}) => {
groups.forEach(group => {
acc[group] = acc[group] || { group, data: [] }
acc[group].data.push(gameId)
})
return acc
}, {}))
console.log(result)
.as-console-wrapper { max-height: 100% !important; top: 0; }
Let arr be the variable containing data in following format:
[
empty,
1: [
id_0, id_2
],
2: [
id_1, id_2
],
3: [
id_3
]
]
Then following code might do:-
for(let i=1;i<arr.length;i++){
arr[i-1] = {group:i,data:arr[i]};
}
arr[arr.length-1] = undefined; // To Prevent Unnecessary Errors
delete arr[arr.length-1]; // To Prevent Unnecessary Errors
arr.length -= -1;
Now arr will be in following format:-
[
{
group: 1,
data: [
id_0, id_2
]
},
{
group: 2,
data: [
id_1, id_2
]
},
{
group: 3,
data: [
id_3
]
}
]
Hope it helps. Tell me if I Misunderstood your question.
Use an object as acc, then add objects to it:
if (acc[key]) {
acc[key].data.push(curr)
} else {
acc[key] = { group: key, data: [curr] };
}
And finally, turn the returned object into an array:
const result = Object.values(hash);
Try this
const data = [
{gameId: 'id_0',groups: [1]},
{gameId: 'id_1',groups: [2]},
{gameId: 'id_2',groups: [1, 2]},
{gameId: 'id_3',groups: [3]}
]
const single_id = data.filter(i => i.groups.length === 1)
const multiple_ids = data.filter(i => i.groups.length > 1)
let res = [];
single_id.map(i => {
let data = {group: i.groups[0], data: [i.gameId]}
multiple_ids.forEach(o => o.groups.includes(i.groups[0]) && (data.data.push(o.gameId)))
res.push(data)
})
console.log(res)
`let b = [
{
gameId: "id_0",
groups: [1]
},
{
gameId: "id_1",
groups: [2]
},
{
gameId: "id_2",
groups: [1, 2]
},
{
gameId: "id_3",
groups: [3]
}
];
let d = new Map(); ;
b.forEach(function(a){
a.groups.forEach(function(a1){
if(d.get(a1)){
d.get(a1).push(a.gameId);
}else{
d.set(a1, [a.gameId]);
}
});
});`
You should try this one. Using reduce in grouped scenarios is the best thing JavaScript provides us
let arr = [
{
gameId: "id_0",
groups: [1]
},
{
gameId: "id_1",
groups: [2]
},
{
gameId: "id_2",
groups: [1, 2]
},
{
gameId: "id_3",
groups: [3]
}
];
const grouped = arr.reduce((acc, current) => {
for(let x of current.groups){
if(!acc[x]) {
acc[x] = {group: x, data:[current.gameId]}
} else {
acc[x].data.push(current.gameId)
}
}
return acc
},{});
console.log(Object.values(grouped))
I am working with javascript arrays, where i have an array of arrays like,
var arr = [
[ 73.0191641, 33.5720131 ],
[ 73.0191641, 33.5720131 ],
[ 3.0191641, 33.5720131 ],
[ 73.0191641, 33.5720131 ],
[ 73.0191641, 33.5720131 ],
[ 73.0192222, 33.5778921 ],
[ 73.0192222, 33.5778921 ]];
There, i needed to remove the duplicate arrays. I have tried this method but it didn't worked for me, may be i am missing or doing something wrong.
var distinctArr = Array.from(new Set(arr));
Although this method works only for array of objects. If someone can help, please do help. Thanks for your time.
Lodash is great lib for doing this little things.
uniqWith with compare isEqual should resolve your problem.
var arr = [
[ 73.0191641, 33.5720131 ],
[ 73.0191641, 33.5720131 ],
[ 3.0191641, 33.5720131 ],
[ 73.0191641, 33.5720131 ],
[ 73.0191641, 33.5720131 ],
[ 73.0192222, 33.5778921 ],
[ 73.0192222, 33.5778921 ]];
_.uniqWith(arr,_.isEqual)
return -> [Array(2), Array(2), Array(2)]
You can use following approach.
var arr = [ { person: { amount: [1,1] } }, { person: { amount: [1,1] } }, { person: { amount: [2,1] } }, { person: { amount: [1,2] } }, { person: { amount: [1,2] } }];
hash = [...new Set(arr.map(v => JSON.stringify(v)))].map(v => JSON.parse(v));
document.write(`<pre>${JSON.stringify(hash, null, 2)}</pre>`);