Filtering out users that appear in an array of strings - javascript

I am trying to filter out any user whose id appears in an array of strings. I am trying to use a filter() method to do this but strugglign with implementing the logic.
const x = [
{
notebookId: "abc",
notebookUsers: [1, 2, 3, 4],
},
{
notebookId: "cde",
notebookUsers: [2, "foo", 4, 3],
},
{
notebookId: "fgh",
notebookUsers: ["bla", 4, 5, "123"],
},
{
notebookId: "qqq",
notebookUsers: [33, 16, 12],
},
{
notebookId: "ab",
notebookUsers: ["abc", 23213, 2131, 33],
},
];
const y = ["abc", "123", "bla", "foo"];
const filteredUsersArray = x.filter((nb) => {
const filteredUsers = nb.notebookUsers.filter(
(user) => !y.includes(user)
);
return (
nb.notebookId !== "welcome" &&
nb.notebookId !== "null" &&
nb.notebookId !== "1234" &&
filteredNotebookUsers.length > 0
);
});
console.log(filteredUsersByNotebookArray);
Result:
[
{
notebookId: "abc",
notebookUsers: [1, 2, 3, 4, 2, "foo", 4, 3]
},
{
notebookId: "cde",
notebookUsers: [2, "foo", 4, 3]
},
{
notebookId: "fgh",
notebookUsers: ["bla", 4, 5, "123"]
},
{
notebookId: "qqq",
notebookUsers: [33, 16, 12, "abc", 23213, 2131, 33]
},
{
notebookId: "ab",
notebookUsers: ["abc", 23213, 2131, 33]
}
]
This doesn't appear to remove the forbidden ids. Not sure where i am wrong.

you are returning a check on a variable called filteredNotebookUsers which does not exist, update the return statement to check the length of the filteredUsers array
const x = [
{
notebookId: "abc",
notebookUsers: [1, 2, 3, 4],
},
{
notebookId: "cde",
notebookUsers: [2, "foo", 4, 3],
},
{
notebookId: "fgh",
notebookUsers: ["bla", 4, 5, "123"],
},
{
notebookId: "qqq",
notebookUsers: [33, 16, 12],
},
{
notebookId: "ab",
notebookUsers: ["abc", 23213, 2131, 33],
},
];
const y = ["abc", "123", "bla", "foo"];
const filteredUsersArray = x.filter((nb) => {
const filteredUsers = nb.notebookUsers.filter(
(user) => !y.includes(user)
);
return (
nb.notebookId !== "welcome" &&
nb.notebookId !== "null" &&
nb.notebookId !== "1234" &&
filteredUsers.length > 0
);
});
console.log(filteredUsersArray);

It seems that filter doesn't do quite what you expect.
Consider this small example:
const userIds = [1,2,3,4];
const filteredUserIds = userIds.filter(id => id >= 3);
console.log(userIds); // [1,2,3,4]
console.log(filteredUserIds); // [3,4]
filter does not change the array that it is filtering
It looks like what you want to do is to map the notebooks so that the users are filtered, and then filter the mapped notebooks:
const filteredNotebooks =
x.map((nb) => {
const filteredUsers = nb.notebookUsers.filter(
(user) => !y.includes(user)
);
return { ...nb, notebookUsers: filteredUsers };
}).filter((nb) => {
return (
nb.notebookId !== "welcome" &&
nb.notebookId !== "null" &&
nb.notebookId !== "1234" &&
nb.notebookUsers.length > 0
);
});

I'm not sure if i understood what you are trying to achieve.
Maybe it is the following:
'Before' [
{
notebookId: 'abc',
notebookUsers: [ 1, 2, 3, 4 ]
},
{
notebookId: 'cde',
notebookUsers: [ 2, 'foo', 4, 3 ]
},
{
notebookId: 'fgh',
notebookUsers: [ 'bla', 4, 5, '123' ]
},
{
notebookId: 'qqq',
notebookUsers: [ 33, 16, 12 ]
},
{
notebookId: 'ab',
notebookUsers: [ 'abc', 23213, 2131, 33 ]
}
]
'After' [
{
notebookId: 'abc',
notebookUsers: [ 1, 2, 3, 4 ]
},
{ notebookId: 'cde', notebookUsers: [ 2, 4, 3 ] },
{ notebookId: 'fgh', notebookUsers: [ 4, 5 ] },
{
notebookId: 'qqq',
notebookUsers: [ 33, 16, 12 ]
},
{
notebookId: 'ab',
notebookUsers: [ 23213, 2131, 33 ]
}
]
Here is the code to return the same Array but without the forbiddenIDs
const forbiddenIDs = ["abc", "123", "bla", "foo"];
const filteredUsersArray = notebooksArray.map((nb) => {
const filteredUsers = nb.notebookUsers.filter(
(user) => !forbiddenIDs.includes(user)
);
return (
nb.notebookId !== "welcome" &&
nb.notebookId !== "null" &&
nb.notebookId !== "1234" &&
filteredUsers.length > 0
) && { notebookId: nb.notebookId, notebookUsers: filteredUsers};
});
console.log(filteredUsersArray);
.map returns a new Array that will be stored in filteredUsersArray.
With && { notebookId: nb.notebookId, notebookUsers: filteredUsers}; we mean that if the previous condition is true we return an object like we had before but with the filtered users. So we add the same notebookId that we had before, and the notebookUsers array will now contain the filtered users.

I don't know exactly what you are wanting. But you can try in this way -
const x = [
{
notebookId: "abc",
notebookUsers: [1, 2, 3, 4],
},
{
notebookId: "cde",
notebookUsers: [2, "foo", 4, 3],
},
{
notebookId: "fgh",
notebookUsers: ["bla", 4, 5, "123"],
},
{
notebookId: "qqq",
notebookUsers: [33, 16, 12],
},
{
notebookId: "ab",
notebookUsers: ["abc", 23213, 2131, 33],
},
];
const y = ["abc", "123", "bla", "foo"];
const filteredUsersArray = x.filter((nb) => {
return nb.notebookUsers.filter(
(user) => !y.includes(user)
)
});
console.log(filteredUsersArray);

Related

Find and group common elements across objects in an array

I am trying to figure out how to map a new array of objects that kind of creates teams by checking each array of users and, where there is a common users, moving that entire array into a new property that also features the notebookIds in common.
I have an array of objects structured like so:
const usersByNotebooks =
[
{
"notebookId": "abc",
"users": [1, 2, 3, 4]
},
{
"notebookId": "cde",
"users": [2, 3, 4]
},
{
"notebookId": "fgh",
"users": [3, 4, 5]
},
{
"notebookId": "qqq",
"users": [33, 16, 12]
},
]
So for the above data it would become something like this:
const teams =
[
{
"notebooksOnTeam": ["abc", "cde", "fgh"],
"usersOnTeam": [1, 2, 3, 4, 5]
},
{
"notebooksOnTeam": "qqq",
"usersOnTeam": [33, 16, 12]
},
]
I am using javascript and having trouble getting the logic down.
Loop over objects of array using reduce and check:
If the current notebook's users don't match any existing team with find method, so create a new team.
If the current notebook's users match an existing team, add the notebook to that team.
const usersByNotebooks = [{ "notebookId": "abc", "users": [1, 2, 3, 4] }, { "notebookId": "cde", "users": [2, 3, 4] }, { "notebookId": "fgh", "users": [3, 4, 5] }, { "notebookId": "qqq", "users": [33, 16, 12] }, ];
const teams = usersByNotebooks.reduce((result, current) => {
const teamFound = result.find((team) => team.usersOnTeam.some((user) => current.users.includes(user)));
if (!teamFound) {
result.push({
notebooksOnTeam: [current.notebookId],
usersOnTeam: current.users
});
} else {
teamFound.notebooksOnTeam.push(current.notebookId);
current.users.forEach((user) => {
if (!teamFound.usersOnTeam.includes(user)) {
teamFound.usersOnTeam.push(user);
}
});
}
return result;
}, []);
console.log(teams)
You could have a look to any objects of the result set and either get the first object of the same group and add all other found and finally add the actual value or later add a new object.
This approach works for unsorted and not connected items which gets later a joint.
const
addIfNotExist = (array, value) => array.includes(value) || array.push(value),
usersByNotebooks = [{ notebookId: "abc", users: [1, 2, 3, 4] }, { notebookId: "cde", users: [2, 3, 4] }, { notebookId: "fgh", users: [3, 4, 5] }, { notebookId: "qqq", users: [33, 16, 12] }, { notebookId: "xxx", users: [6, 7] }, { notebookId: "yyy", users: [5, 6] }],
result = usersByNotebooks.reduce(
(r, { notebookId, users }) => users.reduce((s, user) => {
const objects = [];
let first;
for (const o of s) {
if (!o.users.includes(user) && !o.notebooks.includes(notebookId)) {
objects.push(o);
continue;
}
if (!first) objects.push(first = o);
o.users.forEach(addIfNotExist.bind(null, first.users));
o.notebooks.forEach(addIfNotExist.bind(null, first.notebooks));
}
if (first) {
addIfNotExist(first.users, user);
addIfNotExist(first.notebooks, notebookId);
} else {
objects.push({ users: [user], notebooks: [notebookId] });
}
return objects;
}, r),
[]
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
This is an abstract solution for any length of groups which are connected.
It works in three step:
Generate an array of pairs or more or less items in a tupel,
group connected items together in an aray of arrays and
map the items in the wanted format.
const
addIfNotExist = (array, value) => array.includes(value) || array.push(value),
groupConnectedParts = (r, a) => {
const objects = [];
let first;
for (const b of r) {
if (!a.some((v, i) => b[i].includes(v))) {
objects.push(b);
continue;
}
if (!first) objects.push(first = b);
b.forEach((group, i) => group.forEach(addIfNotExist.bind(null, first[i])));
}
if (first) a.forEach((v, i) => addIfNotExist(first[i], v));
else objects.push(a.map(v => [v]));
return objects;
},
usersByNotebooks = [{ notebookId: "abc", users: [1, 2, 3, 4] }, { notebookId: "cde", users: [2, 3, 4] }, { notebookId: "fgh", users: [3, 4, 5] }, { notebookId: "qqq", users: [33, 16, 12] }, { notebookId: "xxx", users: [6, 7] }, { notebookId: "yyy", users: [5, 6] }],
result = usersByNotebooks
.flatMap(({ notebookId, users }) => users.map(user => [notebookId, user]))
.reduce(groupConnectedParts, [])
.map(([notebooks, users]) => ({ notebooks, users }));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

javascript transfer array to a new array [duplicate]

This question already has answers here:
Most efficient method to groupby on an array of objects
(58 answers)
How can I group an array of objects by key?
(32 answers)
group array of objects by id
(8 answers)
Closed 2 years ago.
I current have one array:
[
{
Id: 14,
userRoleId: 2,
userResourceId: 2,
userActionId: 2,
userScopeId: 2,
},
{
Id: 15,
userRoleId: 3,
userResourceId: 2,
userActionId: 2,
userScopeId: 3,
},
{
Id: 16,
userRoleId: 4,
userResourceId: 2,
userActionId: 2,
userScopeId: 3,
},
{
Id: 17,
userRoleId: 5,
userResourceId: 2,
userActionId: 2,
userScopeId: 1,
}
]
How can I generate the new arrays based on the userScopeId?
The arrays name will be userScopeArrayuserScopeId, and the array content is the userScopeId matching content.
So it will be like:
userScopeIdArray1:
[
{ Id: 17, userRoleId: 5, userResourceId: 2, userActionId: 2 }
]
userScopeIdArray2:
[
{ Id: 14, userRoleId: 2, userResourceId: 2, userActionId: 2 }
]
userScopeIdArray3:
[
{ Id: 15, userRoleId: 3, userResourceId: 2, userActionId: 2 },
{ Id: 16, userRoleId: 4, userResourceId: 2, userActionId: 2,}
]
You could do with Array#reduce
const arr = [ { Id: 14, userRoleId: 2, userResourceId: 2, userActionId: 2, userScopeId: 2, }, { Id: 15, userRoleId: 3, userResourceId: 2, userActionId: 2, userScopeId: 3, }, { Id: 16, userRoleId: 4, userResourceId: 2, userActionId: 2, userScopeId: 3, }, { Id: 17, userRoleId: 5, userResourceId: 2, userActionId: 2, userScopeId: 1, } ];
let res = arr.reduce((acc,cur)=>{
let id = 'userScopeId'+cur['userScopeId'];
acc[id] = acc[id]||[];
acc[id].push(cur);
return acc;
},{});
console.log(res)
You can use reduce array method to build this result.
let input = [
{
Id: 14,
userRoleId: 2,
userResourceId: 2,
userActionId: 2,
userScopeId: 2,
},
{
Id: 15,
userRoleId: 3,
userResourceId: 2,
userActionId: 2,
userScopeId: 3,
},
{
Id: 16,
userRoleId: 4,
userResourceId: 2,
userActionId: 2,
userScopeId: 3,
},
{
Id: 17,
userRoleId: 5,
userResourceId: 2,
userActionId: 2,
userScopeId: 1,
}
];
let output = input.reduce((acc, val) => {
let key = "userScopeIdArray" + val.userScopeId;
if(acc[key]){
acc[key].push(val);
} else{
acc[key] = [val];
}
return acc;
}, {});
console.log(output);

How to filter array with another arrays value

Array One:
[
{ c_id: 6, name: "abc" },
{ c_id: 7, name: "xyz" },
{ c_id: 8, name: "abc12" },
{ c_id: 9, name: "xyz56" },
{ c_id: 10, name: "abc456" }
]
Array Two:
[
{ s_id: 2, s_cid: 6, s_slot: "1" },
{ s_id: 2, s_cid: 6, s_slot: "1" },
{ s_id: 2, s_cid: 6, s_slot: "1" },
{ s_id: 2, s_cid: 10, s_slot: "1" },
{ s_id: 2, s_cid: 10, s_slot: "1" }
]
I want to filter the first array with the second array, by matching c_id and s_cid.
Expected Array:
[{
c_id: 6,
name: "abc",
slot: [{
s_id: 2,
s_cid: 6,
s_slot: "1"
}, {
s_id: 2,
s_cid: 6,
s_slot: "1"
},
{
s_id: 2,
s_cid: 6,
s_slot: "1"
},
]
}, {
c_id: 7,
name: "xyz"
}, {
c_id: 8,
name: "abc12",
slot: []
}, {
c_id: 9,
name: "xyz56",
slot: [{
s_id: 2,
s_cid: 10,
s_slot: "1"
}, {
s_id: 2,
s_cid: 10,
s_slot: "1"
}]
}, {
c_id: 10,
name: "abc456"
}]
Code:
let arr = [];
arr = arr1.filter((el) => {
return el.slot = arr2.filter((el2)=> {
return el. c_id == el2.s_cid
})
})
What am I doing wrong in this code?
Snippet:
const arr1 = [{
c_id: 6,
name: "abc"
}, {
c_id: 7,
name: "xyz"
}, {
c_id: 8,
name: "abc12"
}, {
c_id: 9,
name: "xyz56"
},
{
c_id: 10,
name: "abc456"
}
]
const arr2 = [{
s_id: 2,
s_cid: 6,
s_slot: "1"
}, {
s_id: 2,
s_cid: 6,
s_slot: "1"
}, {
s_id: 2,
s_cid: 6,
s_slot: "1"
},
{
s_id: 2,
s_cid: 10,
s_slot: "1"
}, {
s_id: 2,
s_cid: 10,
s_slot: "1"
}
]
let arr = [];
arr = arr1.filter((el) => {
return el.slot = arr2.filter((el2) => {
return el.c_id == el2.s_cid
})
})
console.log(arr)
You should not filter Array1. Instead you should use map method to create a new array with Array1 to return slot property on each item.
let arr = [];
arr = arr1.map(el=>{
el.slot = arr2.filter(el2=> { return el.c_id == el2.s_cid;})
return el;
})
I think this would work: First replicate arr1 and loop through its' items. For each item filter arr2 with suiting criteria.
const arr1 = [
{c_id: 6,name:"abc"},
{c_id: 7,name:"xyz"},
{c_id: 8,name:"abc12"},
{c_id: 9,name:"xyz56"},
{c_id: 10,name:"abc456"}
];
const arr2 = [
{s_id: 2,s_cid: 6,s_slot:"1"},
{s_id: 2,s_cid: 6,s_slot:"1"},
{s_id: 2,s_cid: 6,s_slot:"1"},
{s_id: 2,s_cid: 10,s_slot:"1"},
{s_id: 2,s_cid: 10,s_slot:"1"}
];
let result = [...arr1];
result.map(x => {
x['slot'] = arr2.filter(y => {
return y.s_cid === x.c_id;
})
});
console.log(result)
#gbalduzzi 's suggestion, less "expensive" one:
const arr1 = [
{c_id: 6,name:"abc"},
{c_id: 7,name:"xyz"},
{c_id: 8,name:"abc12"},
{c_id: 9,name:"xyz56"},
{c_id: 10,name:"abc456"}
];
const arr2 = [
{s_id: 2,s_cid: 6,s_slot:"1"},
{s_id: 2,s_cid: 6,s_slot:"1"},
{s_id: 2,s_cid: 6,s_slot:"1"},
{s_id: 2,s_cid: 10,s_slot:"1"},
{s_id: 2,s_cid: 10,s_slot:"1"}
];
let groups = {};
arr2.map(x => {
const existing = groups[x.s_cid] ? groups[x.s_cid] : [];
groups[x.s_cid] = [...existing, x]
});
arr1.map(x => {
x['slot'] = groups[x.c_id]
});
// arr1 is the result
console.log(arr1)
It's not enough to do it using Array.filter only.
Currently, the first array does not contain slot attribute so the process to put filtered second array to slot will be needed.
That can be done using Array.map.
const arr1 = [{c_id: 6,name:"abc"},{c_id: 7,name:"xyz"},{c_id: 8,name:"abc12"},{c_id: 9,name:"xyz56"},
{c_id: 10,name:"abc456"}];
const arr2 = [{s_id: 2,s_cid: 6,s_slot:"1"},{s_id: 2,s_cid: 6,s_slot:"1"},{s_id: 2,s_cid: 6,s_slot:"1"},
{s_id: 2,s_cid: 10,s_slot:"1"},{s_id: 2,s_cid: 10,s_slot:"1"}];
const result = arr1.map(({ c_id, name }) => ({
c_id,
name,
slot: arr2.filter(({ s_cid }) => c_id === s_cid)
}));
console.log(result);
You could take another approach with just two loops and collect all slots an in object with slot as key and map the first array with the assigned slot or an empty array.
const
data1 = [{ c_id: 6, name: "abc" }, { c_id: 7, name: "xyz" }, { c_id: 8, name: "abc12" }, { c_id: 9, name: "xyz56" }, { c_id: 10, name: "abc456" }],
data2 = [{ s_id: 2, s_cid: 6, s_slot: "1" }, { s_id: 2, s_cid: 6, s_slot: "1" }, { s_id: 2, s_cid: 6, s_slot: "1" }, { s_id: 2, s_cid: 10, s_slot: "1" }, { s_id: 2, s_cid: 10, s_slot: "1" }],
slots = data2.reduce((s, o) => ((s[o.s_cid] = s[o.s_cid] || []).push(o), s), {}),
result = data1.map(o => ({ ...o, slot: slots[o.c_id] || []}));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
const a1 = [
{ c_id: 6, name:"abc" },
{ c_id: 7, name:"xyz" },
{ c_id: 8, name:"abc12" },
{ c_id: 9, name:"xyz56" },
{ c_id: 10, name:"abc456" },
];
const a2 = [
{ s_id: 2, s_cid: 6, s_slot:"1" },
{ s_id: 2, s_cid: 6, s_slot:"1" },
{ s_id: 2, s_cid: 6, s_slot:"1" },
{ s_id: 2, s_cid: 10, s_slot:"1" },
{ s_id: 2, s_cid: 10, s_slot:"1" },
];
const slotArrays = (a, b) => {
return a.map((item) => {
item.slot = b.filter((x) => x.s_cid === item.c_id);
return item;
});
};
console.log(slotArrays(a1, a2));

Merging objects to obtain the average value in arrays

I'm trying to obtain an average value for scores arrays and leave other values from the first object. I can't manage how to loop through the objects to achieve expected output.
const bigArr = [
{
bigDummyData: "string0",
examples: [
{ smallDD: "string00", scores: [1, 1, 5] },
{ smallDD: "string01", scores: [2, 2, 4] },
{ smallDD: "string02", scores: [2, 2, 6] },
],
},
{
bigDummyData: "string1",
examples: [
{ smallDD: "string10", scores: [3, 3, 3] },
{ smallDD: "string11", scores: [2, 2, 2] },
{ smallDD: "string12", scores: [4, 4, 4] },
],
},
]
Expected output its:
output = {
bigDummyData: "string0",
examples: [
{ smallDD: "string00", scores: [2, 2, 4] },
{ smallDD: "string01", scores: [2, 2, 3] },
{ smallDD: "string02", scores: [3, 3, 5] },
],
}
As you can see, bigDummyData and each smallDD are left from the first object.
That's is a simplified example of the problem, arrays bigArr and examples are uploaded dynamically, so they are usually much longer.
May be this will help you
const bigArr = [
{
bigDummyData: "string0",
examples: [
{ smallDD: "string00", scores: [1, 1, 5] },
{ smallDD: "string01", scores: [2, 2, 4] },
{ smallDD: "string02", scores: [2, 2, 6] },
],
},
{
bigDummyData: "string1",
examples: [
{ smallDD: "string10", scores: [3, 3, 3] },
{ smallDD: "string11", scores: [2, 2, 2] },
{ smallDD: "string12", scores: [4, 4, 4] },
],
}
]
let firstElement = bigArr[0];
let length = bigArr.length;
bigArr.splice(0,1)
bigArr.forEach(({examples}) => {
examples.forEach(({scores},i) => {
firstElement.examples[i].scores = firstElement.examples[i].scores.map( (x,j) => x+scores[j]);
})
});
firstElement.examples.forEach(({scores},i) => {
firstElement.examples[i].scores = firstElement.examples[i].scores.map( (x) => x/length);
});
console.log(firstElement);
When to use Map
Creating new array based on doing some operation in existing array.Official Documentation
Splice
The splice() method changes the contents of an array by removing or replacing existing elements and/or adding new elements Official Documentation
Accept this,if it helps you.

Convert Array groups into object

I have an array. And i want to convert them into a group of objects.
below is my array
[ null,
[ 5, 6 ],
[ 7, 8 ],
[ 9, 10 ],
[ 13, 14 ] ]
Then i tried them to convert into object by pairs but what i had was this:
{ '0': null,
'1': [ 5, 6 ],
'2': [ 7, 8 ],
'3': [ 9, 10 ],
'4': [ 13, 14 ] }
What i'm trying to achieve is something like below:
{
"0": 5,
"1": 6,
},
{
"0": 7,
"1": 8,
},
{
"0": 9,
"1": 10,
},
{
"0": 13,
"1": 14,
},
thank you for those who will help
You could filter falsy values and map objects where you have assigned the array.
var array = [null, [5, 6], [7, 8], [9, 10], [13, 14]],
result = array
.filter(Boolean)
.map(a => Object.assign({}, a));
console.log(result);
Wrapped in a function
function getObjects(array) {
return array
.filter(Boolean)
.map(a => Object.assign({}, a));
}
console.log(getObjects([null, [5, 6], [7, 8], [9, 10], [13, 14]]));
You should have a condition that skip the null value in the array:
function changeArray(arr){
var res = [];
arr.forEach((item)=>{
let obj = {};
if(item){
item.forEach((val, index)=>{
obj[index] = val;
});
res.push(obj);
}
});
return res;
}
var arr1 = [ null,
[ 5, 6 ],
[ 7, 8 ],
[ 9, 10 ],
[ 13, 14 ] ];
console.log(changeArray(arr1));
var arr2 = [ null,
[ 5, 6, 7 ],
[ 7, 8, 9 ]];
console.log(changeArray(arr2));

Categories