data = [
{
rows: [
{ name: 'a'}
]
},
{
rows: [
{ name: 'b'}
]
}
{
rows: []
}
]
what I'm trying to do here is to get the rows data. which is like this.
expected output:
data = [
{
name: 'a'
},
{
name: 'b'
}
];
where it will remove the empty array and it will merge on it.
Approach 1:
You can use reduce on your array as below -
var data = [
{
rows: [
{ name: 'a'}
]
},
{
rows: [
{ name: 'b'}
]
},
{
rows: []
}
]
var reducedSet = [];
data.reduce((accumulator, currentValue, currentIndex) => {
var currentRows = currentValue.rows;
var rowLength = currentRows && currentRows.length
if (rowLength) {
for (i = 0; i < rowLength; i++) {
accumulator.push(currentRows[i]);
}
return accumulator;
}
}, reducedSet);
console.log(reducedSet);
Approach 2:
Alternatively, you can also do it as below -
var data = [
{
rows: [
{ name: 'a'}
]
},
{
rows: [
{ name: 'b'}
]
},
{
rows: []
}
];
var result = data.filter(f => f.rows && f.rows.length && f.rows.length > 0).map((currentValue) => {
return currentValue.rows;
}).flat();
console.log(result);
Above code first filters out the empty rows and then maps the out the data and finally flattens the result.
data = [
{
rows: [
{ name: 'a'},
]
},
{
rows: [
{ name: 'b'},
]
},
{
rows: []
}
]
let mappedData = data.map(obj => {
return obj.rows.map(obj2 => {
return {
name: obj2.name
}
})
})
mappedData = mappedData.flat()
console.log(mappedData)
Try something like that, I guess that's what you want from what I've seen.
This might help. The solution provided takes into account that there might be multiple name inside a single rows.
let data = [] // YOUR OBJECT IN THE QUESTION
let data2: any = []
data.forEach(el => {
if(el.rows.length > 0) {
data2 = [...data2, ...el.rows];
}
})
console.log('data2', data2);
If you want to one-line it with modern Javascript, this is the way.
const transform = (inData) => inData.reduce((outData, { rows }) => outData.concat(rows), []);
Basically, create a new array, then for each entry in inData extract the content of the rows property and add it to the array.
data.filter(x => {
x.rows !== [];
});
You could filter the array.
Related
I have this array of objects, within it I have another array of objects:
[
{
id: 1,
country: [
{
id: "5a60626f1d41c80c8d3f8a85"
},
{
id: "5a6062661d41c80c8b2f0413"
}
]
},
{
id: 2,
country: [
{
id: "5a60626f1d41c80c8d3f8a83"
},
{
id: "5a60626f1d41c80c8d3f8a84"
}
]
}
];
How to get flat array of country like this:
[
{ id: "5a60626f1d41c80c8d3f8a85" },
{ id: "5a6062661d41c80c8b2f0413" },
{ id: "5a60626f1d41c80c8d3f8a83" },
{ id: "5a60626f1d41c80c8d3f8a84" }
];
without using a forEach and a temp variable?
When I did:
(data || []).map(o=>{
return o.country.map(o2=>({id: o2.id}))
})
I got the same structure back.
Latest edit
All modern JS environments now support Array.prototype.flat and Array.prototype.flatMap
const data=[{id:1,country:[{id:"5a60626f1d41c80c8d3f8a85"},{id:"5a6062661d41c80c8b2f0413"}]},{id:2,country:[{id:"5a60626f1d41c80c8d3f8a83"},{id:"5a60626f1d41c80c8d3f8a84"}]}];
console.log(
data.flatMap(
(elem) => elem.country
)
)
Old answer
No need for any ES6 magic, you can just reduce the array by concatenating inner country arrays.
const data=[{id:1,country:[{id:"5a60626f1d41c80c8d3f8a85"},{id:"5a6062661d41c80c8b2f0413"}]},{id:2,country:[{id:"5a60626f1d41c80c8d3f8a83"},{id:"5a60626f1d41c80c8d3f8a84"}]}];
console.log(
data.reduce(
(arr, elem) => arr.concat(elem.country), []
)
)
If you want an ES6 feature (other than an arrow function), use array spread instead of the concat method:
const data=[{id:1,country:[{id:"5a60626f1d41c80c8d3f8a85"},{id:"5a6062661d41c80c8b2f0413"}]},{id:2,country:[{id:"5a60626f1d41c80c8d3f8a83"},{id:"5a60626f1d41c80c8d3f8a84"}]}];
console.log(
data.reduce(
(arr, elem) => [...arr, ...elem.country], []
)
)
Note: These suggestions would create a new array on each iteration.
For efficiency, you have to sacrifice some elegance:
const data=[{id:1,country:[{id:"5a60626f1d41c80c8d3f8a85"},{id:"5a6062661d41c80c8b2f0413"}]},{id:2,country:[{id:"5a60626f1d41c80c8d3f8a83"},{id:"5a60626f1d41c80c8d3f8a84"}]}];
console.log(
data.reduce(
(arr, elem) => {
for (const c of elem.country) {
arr.push(c);
}
return arr;
}, []
)
)
const raw = [
{
id: 1,
country: [
{
id: "5a60626f1d41c80c8d3f8a85"
},
{
id: "5a6062661d41c80c8b2f0413"
}
]
},
{
id: 2,
country: [
{
id: "5a60626f1d41c80c8d3f8a83"
},
{
id: "5a60626f1d41c80c8d3f8a84"
}
]
}
];
const countryIds = raw
.map(x => x.country)
.reduce((acc, curr) => {
return [
...acc,
...curr.map(x => x.id)
];
}, []);
console.log(countryIds)
This, works, just concat the nested arrays returned by your solution
let arr = [{ "id": 1,
"country": [{
"id": "5a60626f1d41c80c8d3f8a85",
},
{
"id": "5a6062661d41c80c8b2f0413",
}
]
},
{
"id": 2,
"country": [{
"id": "5a60626f1d41c80c8d3f8a83",
},
{
"id": "5a60626f1d41c80c8d3f8a84",
}
]
}
];
//If you want an array of country objects
console.log([].concat.apply(...(arr || []).map(o=> o.country)))
//If you can an array od country ids
console.log([].concat.apply(...(arr || []).map(o=> o.country.map(country => country.id))))
Ayush Gupta's solution will work for this case. But I would like to provide other solution.
const arr = [
{
id: 1,
country: [
{
id: '5a60626f1d41c80c8d3f8a85'
},
{
id: '5a6062661d41c80c8b2f0413'
}
]
},
{
id: 2,
country: [
{
id: '5a60626f1d41c80c8d3f8a83'
},
{
id: '5a60626f1d41c80c8d3f8a84'
}
]
}
];
const ids = arr.reduce(
(acc, {country}) => [
...acc,
...country.map(({id}) => ({
id
}))
],
[]
);
console.log(ids);
For JSON string data, it can be done during parsing too :
var ids = [], json = '[{"id":1,"country":[{"id":"5a60626f1d41c80c8d3f8a85"},{"id":"5a6062661d41c80c8b2f0413"}]},{"id":2,"country":[{"id":"5a60626f1d41c80c8d3f8a83"},{"id":"5a60626f1d41c80c8d3f8a84"}]}]';
JSON.parse(json, (k, v) => v.big && ids.push(v));
console.log( ids );
I am not sure why noone mentioned flat() (probably for large arrays, it might be less performant)
(data || []).map(o=>{
return o.country.map(o2=>({id: o2.id}))
}).flat()
I have array of objects, in which the keys matches,
then return the array of object using javascript
for example,
Passing param zapp is found in arr, return those objects in array using
javascript
var arr =[
{id:1, keys: "zapp"},
{id:2, keys: "zapp, zoin"},
{id:3, keys: "dell"}
];
tried
function checkKeys (arr, keytocheck) {
let result=[]
if(arr.length > 0){
for(let elem of arr) {
const splitkeys = elem.keys(',');
if(elem.keys.indexOf(',') > -1) {
// comma have
if(splitKeys.includes(keytocheck)){
result.push(elem);
}
}
else {
// no comma
if(elem.keys === keytocheck) {
result.push(elem);
}
}
}
}
return result
};
console.log(checkKeys(arr, "zapp"));
Expected Output
[
{id:1, keys: "zapp"},
{id:2, keys: "zapp, zoin"}
]
You are missing split in:
const splitkeys = elem.keys(','); // HERE keys is a string not a function
You have to use split here as:
const splitkeys = elem.keys.split(',');
var arr = [
{ id: 1, keys: 'zapp' },
{ id: 2, keys: 'zapp, zoin' },
{ id: 3, keys: 'dell' },
];
function checkKeys(arr, keytocheck) {
let result = [];
if (arr.length > 0) {
for (let elem of arr) {
const splitkeys = elem.keys.split(',');
if (elem.keys.indexOf(',') > -1) {
// comma have
if (splitkeys.includes(keytocheck)) {
result.push(elem);
}
} else {
// no comma
if (elem.keys === keytocheck) {
result.push(elem);
}
}
}
}
return result;
}
console.log(checkKeys(arr, 'zapp'));
ALTERNATE SOLUTION 1
You can use filter and includes here as:
var arr = [
{ id: 1, keys: 'zapp' },
{ id: 2, keys: 'zapp, zoin' },
{ id: 3, keys: 'dell' },
];
function checkKeys(arr, keytocheck) {
return arr.filter((o) => o.keys.includes(keytocheck));
}
console.log(checkKeys(arr, 'zapp'));
ALTERNATE SOLUTION 2
You can use regex also here as:
var arr = [
{ id: 1, keys: 'zapp' },
{ id: 2, keys: 'zapp, zoin' },
{ id: 3, keys: 'dell' },
];
function checkKeys(arr, keytocheck) {
const regex = new RegExp(keytocheck);
return arr.filter((o) => o.keys.match(regex));
}
console.log(checkKeys(arr, 'zapp'));
You can use filter method
const array = [
{ id: 1, keys: 'zapp' },
{ id: 2, keys: 'zapp, zoin' },
{ id: 3, keys: 'dell' },
];
function filterByKeyValue(arr, key){
return arr.filter((el) => el.keys.toLowerCase().includes(key.toLowerCase()));
}
console.log(filterByKeyValue(array, 'zapp'));
Given the output, I want to list <li> dynamically
results = [
{
name: 'a1',
results: []
},
{
name: 'a2',
results: [
{
name: 'b1',
results: []
},
{
name: 'b2',
results: [
{
name: 'c1',
}
]
}
]
},
{
name: 'a3',
}
]
This is expected output
<li>a1</li>
<li>a2</li>
<li>b1</li>
<li>b2</li>
<li>c1</li>
<li>a3</li>
My pseudo-code but I think this is not even close... I think I need "recursive" solution to tackle this problem
input.map((r) => {
if(r) {
return renderResult(r);
} <<< This is not a recursive way...
return renderResult(r.results.?);
});
How do I list this dynamically and recursively?
Your solution is nearly this one
function generate(arr) {
const items = [];
arr.forEach( i => {
items.push(i.name); //Or whatever you want
});
return items;
}
Just introduce recursivity
function generate(arr) {
const items = [];
arr.forEach( i => {
items.push(i.name);
if( !!i.results ){
const subs = generate(i.results);
subs.forEach( s => items.push(s));
}
});
return items;
}
Here's my take on the problem!
For dynamically inserting the li tags into the dom, use createElement and append!
const results = [
{
name: 'a1',
results: []
},
{
name: 'a2',
results: [
{
name: 'b1',
results: []
},
{
name: 'b2',
results: [
{
name: 'c1',
}
]
}
]
},
{
name: 'a3',
}
]
const getNames = (list) => {
const names = [];
function getDeepNames(list) {
for (let obj of list) {
names.push(obj.name);
if (Array.isArray(obj.results)) {
getDeepNames(obj.results);
}
}
return names;
}
return getDeepNames(list)
}
console.log(getNames(results))
I have the following array:
[{
name: 'foo',
values: '10,12'
},
{
name: 'bar',
values: 'red,blue'
}]
Using some javascript logic I would like to output the following array:
[{
option1: 10,
option2: 'red'
},
{
option1: 10,
option2: 'blue'
},
{
option1: 12,
option2: 'red'
},
{
option1: 12,
option2: 'blue'
}]
What is the best and correct way to achieve this using javascript?
Lets say your first array is named arr.
var arr = [{
name: 'foo',
values: '10,12'
},
{
name: 'bar',
values: 'red,blue'
}];
var v1 = arr[0].values.split(',');
var v2 = arr[1].values.split(',');
var res = new Array();
for(i in v1){
for(j in v2){
res.push({'option1':v1[i],'option2':v2[j]});
}
}
console.log(res);
Here's an approach that can handle an arbitrary number of objects.
function valuesCrossProduct(input) {
return input.flatMap((current, index, array) => {
let result = [];
let values = current.values.split(',');
for (let v of values) {
for (let i = 0; i < array.length; i++) {
if (i <= index) {
// Skip creating cross products with self (i.e. == index)
// and with previously visited objects (i.e. < index).
continue;
}
let iValues = array[i].values.split(',');
let currentKey = `option${index}`;
let iKey = `option${i}`;
for (let iv of iValues) {
result.push({
[currentKey]: v,
[iKey]: iv,
});
}
}
}
return result;
});
}
let twoElementArray = [{
name: 'foo',
values: '10,12'
},
{
name: 'bar',
values: 'red,blue',
}];
let threeElementArray = [{
name: 'foo',
values: '10,12'
},
{
name: 'bar',
values: 'red,blue',
},
{
name: 'baz',
values: 'wham,bam',
}];
console.log(valuesCrossProduct(twoElementArray));
console.log(valuesCrossProduct(threeElementArray));
Functional for the win.
Note: as it is, this only works for an array of two objects, with any number of values in each, where the first set of values are numbers and the second set are strings, which is what you described above.
const arr = [{
name: 'foo',
values: '10,12'
},
{
name: 'bar',
values: 'red,blue'
}];
const values = arr
.map(o => o.values.split(','))
.reduce((cur, next) => {
return cur.map(c => {
return next.map(n => {
return {
option1: parseInt(c),
option2: n
};
});
}).flat();
});
console.log(values);
If you need generic approach to get possible options from various values.
const options = data => {
let sets = [[]];
data.forEach(({ values }, i) => {
const new_set = [];
values.split(",").forEach(value => {
new_set.push(
Array.from(sets, set => [...set, [`option${i + 1}`, value]])
);
});
sets = new_set.flatMap(set => set);
});
return sets.map(set => Object.fromEntries(set));
};
const data = [
{
name: "foo",
values: "10,12"
},
{
name: "bar",
values: "red,blue,green"
},
{
name: "test",
values: "top,bottom"
}
];
console.log(options(data));
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))