Reputation: 1528
I would like to copy an array so as not to modify the original, and remove all selected: false from new array, and return this new array. The array is infinitely nested, and with infinite property names non of which are predictable, so this should be possible through iteration looking at the value of each property for Array.isArray(). While I can remove selected:false objects in the iteration, I fail to return the modified array back to the new array.
function failing to filter aliens. Also, function works in CodePen, but not in my code.
// sample nested data
var data = [
{
partyId: "animal-ID-001",
selected: false,
members: [
{
selected: false,
userId: "animal-user-3443"
},
{
selected: false,
userId: "animal-user-3444"
}
]
},
{
partyId: "benjamin-ID-002",
selected: true,
members: [
{
selected: true,
userId: "benjamin-user-5567",
teams: [
{
selected: true,
teamId: "team-benjamin-678"
},
{
selected: false,
teamId: "team-benjamin-3468"
}
]},
{
selected: false,
userId: "benjamin-user-55671"
}
]
},
{
partyId: "crystal-ID-003",
selected: true,
members: [
{
selected: true,
userId: "crystal-user-8567"
},
{
selected: true,
userId: "crystal-user-85671"
}
],
aliens: [
{
selected: false,
alienId: "crystal-alien-467"
},
{
selected: false,
alienId: "crystal-alien-230"
}
]
}
];
// remove selected false from array
// updated per suggestions
function updateState(arr) {
return arr.filter(obj => obj.selected ).map( obj => {
for (var prop in obj) {
if( Array.isArray( obj[prop] ) ) {
return { ...obj, [prop]: updateState( obj[prop] ) };
}
}
return { ...obj }
});
}
console.log( updateState( data ) );
Upvotes: 0
Views: 73
Reputation: 50787
Does something like this work for you?:
const removeNonselected = (x) =>
Array .isArray (x)
? x .reduce (
(all, item) => item .selected === false
? all
: all .concat (removeNonselected (item)),
[]
)
: typeof x == 'object'
? Object .fromEntries (
Object .entries (x) .map(([n, v]) => [n, removeNonselected(v)])
)
: x
const data = [{partyId: "animal-ID-001", selected: false, members: [{selected: false, userId: "animal-user-3443"}, {selected: false, userId: "animal-user-3444"}]}, {partyId: "benjamin-ID-002", selected: true, members: [{selected: true, userId: "benjamin-user-5567", teams: [{selected: true, teamId: "team-benjamin-678"}, {selected: false, teamId: "team-benjamin-3468"}]}, {selected: false, userId: "benjamin-user-55671"}]}, {partyId: "crystal-ID-003", selected: true, members: [{selected: true, userId: "crystal-user-8567"}, {selected: true, userId: "crystal-user-85671"}], aliens: [{selected: false, alienId: "crystal-alien-467"}, {selected: false, alienId: "crystal-alien-230"}]}];
console .log (removeNonselected (data))
console .log ('original data unchanged:')
console .log (data)
This handles three cases: where the data is an array, where it's an object, or where it's something else. For an array we keep only the selected ones (where selected
is not false
) and recurs on those values. For an object, we keep other values intact, but recur on array properties. Anything else we just return as is.
This does not remove a selected: false
property of an object, only from within an array. It would not be much harder to add that, but it didn't seem to be in your requirements.
If you environment doesn't support Object.fromEntries
, it's fairly easy to shim.
Upvotes: 1
Reputation: 11080
Don't reinvent the wheel, check what functions you can use on arrays. Array.filter
with recursion is perfect here:
var data=[{partyId:"animal-ID-001",selected:!1,members:[{selected:!1,userId:"animal-user-3443"},{selected:!1,userId:"animal-user-3444"}]},{partyId:"benjamin-ID-002",selected:!0,members:[{selected:!0,userId:"benjamin-user-5567"},{selected:!1,userId:"benjamin-user-55671"}]},{partyId:"crystal-ID-003",selected:!0,members:[{selected:!0,userId:"crystal-user-8567"},{selected:!0,userId:"crystal-user-85671"}]}];
function removeNonselected(arr) {
return arr.filter(obj => obj.selected).map(obj => {
if(obj.members) return { ...obj, members: removeNonselected(obj.members) };
else return { ...obj }
});
}
console.log(removeNonselected(data));
Upvotes: 0
Reputation: 51
Try this simple one:
let selectedParties = data.filter(item => item.selected);
let partiesWithSelectedMembersOnly = selectedParties.map(item => {
return {
...item,
members: item.members.filter(member => member.selected)
};
});
Array.filter() returns new array, so you will not modify initial one.
Upvotes: 0
Reputation: 370689
First .filter
the original data, removing items with selected: false
, then .map
the result, and inside the callback, return the same object while .filter
ing the members
property. Then
var data = [{
partyId: "animal-ID-001",
selected: false,
members: [{
selected: false,
userId: "animal-user-3443"
},
{
selected: false,
userId: "animal-user-3444"
}
]
},
{
partyId: "benjamin-ID-002",
selected: true,
members: [{
selected: true,
userId: "benjamin-user-5567"
},
{
selected: false,
userId: "benjamin-user-55671"
}
]
},
{
partyId: "crystal-ID-003",
selected: true,
members: [{
selected: true,
userId: "crystal-user-8567"
},
{
selected: true,
userId: "crystal-user-85671"
}
]
}
];
const updatedData = data
.filter(({ selected }) => selected)
.map(({ members, ...rest }) => ({
...rest,
members: members.filter(({ selected }) => selected)
}));
console.log(updatedData);
Upvotes: 1