best way to get unique values of 2 arrays which different structure? - javascript

I have 2 arrays like this:
blockedUsers = ['u1', 'u2', 'u3']
videoList = [
{
id: 1,
mp4URL: '...mp4',
user: {
id: 'u1',
name: 'User 1'
}
},
{
id: 2,
mp4URL: '...mp4',
user: {
id: 'u2',
name: 'User 1'
}
},
{
id: 3,
mp4URL: '...mp4',
user: {
id: 'u5',
name: 'User 1'
}
}
]
I want to remove blocked users from video array. At final I will get array has 1 video from u5. How to do that?
Thank you

Filter out elements where user id is not included in blocked users.
videoList.filter(v => !blockedUsers.includes(v.user.id))

There are a lot of methods for the same. Please find Array.filter implementation of the same.
const blockedUsers = ['u1', 'u2', 'u3']
const videoList = [
{ id: 1, mp4URL: '...mp4', user: { id: 'u1', name: 'User 1' } },
{ id: 2, mp4URL: '...mp4', user: { id: 'u2', name: 'User 1' } },
{ id: 3, mp4URL: '...mp4', user: { id: 'u5', name: 'User 1' } }
];
const output = videoList.filter((node) => blockedUsers.indexOf(node.user.id) === -1);
console.log(output);

There are two ways
First way, you could filter the videoList and iterate to check if the user is in the blocked list. We could do this with .includes for blockedUsers, but this way will result in the complexity of O(n*m), given that n is the length of blockedUsers and m is the length of videoList
Second way, you could first turn the blockedUsers into a hash table using Set. This will reduce the query time complexity for blockedUsers from O(n) to O(1). In this way, the overall time complexity would be O(n + m), which is better than the first way
const blockedUsers = ["u1", "u2", "u3"]
const videoList = [ { id: 1, mp4URL: "...mp4", user: { id: "u1", name: "User 1", }, }, { id: 2, mp4URL: "...mp4", user: { id: "u2", name: "User 1", }, }, { id: 3, mp4URL: "...mp4", user: { id: "u5", name: "User 1", }, }, ]
const blockedUsersHashTable = new Set(blockedUsers)
const res = videoList.filter(
({ user: { id } }) => !blockedUsersHashTable.has(id)
)
console.log(res)
If time complexity is not your concern, just go with the first way.

You can filter the list by using the Array.prototype.includes() method.
const
blockedUsers = ['u1', 'u2', 'u3'],
videoList = [
{ id: 1, mp4URL: '...mp4', user: { id: 'u1', name: 'User 1' } },
{ id: 2, mp4URL: '...mp4', user: { id: 'u2', name: 'User 1' } },
{ id: 3, mp4URL: '...mp4', user: { id: 'u5', name: 'User 1' } }
],
allowedVideos = videoList.filter(({ user: { id } }) => !blockedUsers.includes(id));
console.log(allowedVideos);
.as-console-wrapper { top: 0; max-height: 100% !important; }

const blockedUsers = ['u1', 'u2', 'u3'];
const videoList = [
{
id: 1,
mp4URL: '...mp4',
user: {
id: 'u1',
name: 'User 1'
}
},
{
id: 2,
mp4URL: '...mp4',
user: {
id: 'u2',
name: 'User 1'
}
},
{
id: 3,
mp4URL: '...mp4',
user: {
id: 'u5',
name: 'User 1'
}
}
];
const target = videoList.filter(v => !blockedUsers.includes(v.user.id));
console.log(target);

Related

comparing objects in useState and if there is object with same id keep one of them

i'm react beginner, for some reason when i console log i get two japans any advices ?
these are my data:
options initial value (comes from props) is:
[{ id: 1, name: 'Japan' },{ id: 4, name: 'Australia' }, { id: 5, name: 'Poland' }];
and from redux i'm getting this:
[{ id: 1, name: 'Japan' }, { id: 2, name: 'America' }, { id: 3, name: 'Sweden' }];
but my expected out put is :
[{ id: 1, name: 'Japan' },{ id: 4, name: 'Australia' }, { id: 5, name: 'Poland' }, { id: 2, name: 'America' }, { id: 3, name: 'Sweden' }]
const getUnselectedValues = useSelector(UnselectedValues);
const [options, setOptions] = useState(
props.selectedValues
? (
[...props.selectedValues, ...getUnselectedValues]
).filter((e ) => e)
: [...getUnselectedValues]
);
console.log('options:', options)
Try it:
const [options, setOptions] = useState(
props.selectedValues
? Object.values([...props.selectedValues, ...getUnselectedValues].reduce((acc, {id, name}) =>(acc[id] ??= {id, name}, acc),{}))
: [...getUnselectedValues]
);
Approach:
Iterate through the merged array and build a dictionary by using reduce() where the key is the id and the value is {id, value}
In every iteration look up in the dictionary whether has the key in it or not. If the key is not present that means it's a unique entry and inserts it. If the key is already in the dictionary that means the entry is not unique so no need to insert it again.
Here is an example in Vanilla JS so you can play around:
const selectedValues = [{ id: 1, name: 'Japan' },{ id: 4, name: 'Australia' }, { id: 5, name: 'Poland' }];
const getUnselectedValues = [{ id: 1, name: 'Japan' }, { id: 2, name: 'America' }, { id: 3, name: 'Sweden' }];
const res = Object.values([...selectedValues, ...getUnselectedValues].reduce((acc, {id, name}) =>(acc[id] ??= {id, name}, acc),{}));
console.log(res);
Using filter():
const selectedValues = [{ id: 1, name: 'Japan' },{ id: 4, name: 'Australia' }, { id: 5, name: 'Poland' }];
const getUnselectedValues = [{ id: 1, name: 'Japan' }, { id: 2, name: 'America' }, { id: 3, name: 'Sweden' }];
const res = [...selectedValues, ...getUnselectedValues.filter(({id, name}) => !selectedValues.find(it => it.id === id))];
console.log(res);

How to change object value in array with objects with if/else in JS

I have an array with objects. I need to find item with current name and change it.
const example = [
{
id: '1234',
desc: 'sample1',
items: [
itemsName: [
{ id: 1, name: 'name1' },
{ id: 2, name: 'testItem2' }
],
id: 888,
]
},
{
id: '3456',
desc: 'sample2',
items: [
itemsName: [
{ id: 1, name: 'name2' },
{ id: 2, name: 'testItem3' }
],
id: 889,
]
},
I try to do in this way, but it's not working.
I get construction like (5) 
[Array(1), Array(1)]
instead of 
[{…}, {…}]
const findName = (name, changedName) => {
const result = example?.map((group) =>
group.items.map((group) =>
group.itemsName?.map((i) => {
if (i.name === name) return i.name === changedName;
return null;
})
)
);
}
findName('name1', 'name2')
let findName1 = (name, changedName) => {
const result = example?.map((group) =>
group.items.map((group) =>
group.itemsName?.map((i) => {
if (i.name === name) return i.name = changedName;
return null;
})
)
);
}
This will work with following object (your object declaration seems to be wrong)
const example = [
{
id: '1234',
desc: 'sample1',
items: [
{itemsName: [
{ id: 1, name: 'name1' },
{ id: 2, name: 'testItem2' }
],
id: 888,}
]
},
{
id: '3456',
desc: 'sample2',
items: [
{itemsName: [
{ id: 1, name: 'name2' },
{ id: 2, name: 'testItem3' }
],
id: 889,}
]
}]

Filter data from Array of Objects contains Array of Objects

Here I have attendance details and I Want to filter every data that contains employees id:1.
for example: I have data like this:
const attendance = [
{
date: 1,
employees: [
{
id: 1,
name: 'mahadev',
status: 'p'
},
{
id: 2,
name: 'roshan',
status: 'p'
},
]
},
{
date: 2,
employees: [
{
id: 1,
name: 'mahadev',
status: 'a'
},
{
id: 2,
name: 'roshan',
status: 'p'
},
]
},
];
And I want Output like this:
[
{
date:1,
employees: [
{
id:1,
name:'mahadev',
status:'p'
}
]
},
{
date:2,
employees: [
{
id:1,
name:'mahadev',
status:'a'
}
]
},
]
Try using map and filter.
const attendance = [{
date: 1,
employees: [
{ id: 1, name: 'mahadev', status: 'p' },
{ id: 2, name: 'roshan', status: 'p' }
]
},
{
date: 2,
employees: [
{ id: 1, name: 'mahadev', status: 'a' },
{ id: 2, name: 'roshan', status: 'p' }
]
},
];
const filtered = id =>
attendance.map(a => {
const employees = a.employees.filter(e => e.id === id);
return { ...a, employees };
});
console.log(filtered(1));
Using map() and filter()
const filtered = id =>
attendance.map(a => {
const employees = a.employees.filter(emp => emp.id === id);
return { date:a.date, employees };
});
console.log(filtered(1))

JavaScript search Object Array and return index of parent

I have been looking around for a JavaScript method to return the index of a value but I can't seem to find one that works.
I have the following code:
let topics = [
{
id: 1,
name: 'Topic 1',
children: [
{
id: 2,
name: 'Subtopic 1.1' <---- Searching for this value
}
]
}
];
Is there a method to use on the topics variable to search through the entire object array at once for the value of Subtopic 1.1 and then return the parent index, which in this case would be 0.
There isn't a single function, but you can nest an Array.prototype.find function inside an Array.prototype.findIndex without issue to achieve what you want (findIndex to search through the parents, find to search through the children):
let topics = [{
id: 1,
name: 'Topic 1',
children: [{
id: 2,
name: 'Subtopic 1.1' // <---- Searching for this value
}]
},
{
id: 2,
name: 'Topic 6',
children: [{
id: 5,
name: 'Subtopic 1.7'
}]
},
{
id: 3,
name: 'Topic 9',
children: [{
id: 4,
name: 'Subtopic 1.192'
},
{
id: 28,
name: 'Subtopic 999'
}],
},
];
function findParentIndex(name) {
return topics.findIndex(topic => topic.children.find(child => child.name === name));
}
console.log(findParentId("Subtopic 1.192")); // 3
console.log(findParentId("Subtopic 1.1")); // 1
console.log(findParentId("Not in the list")); // -1
You can use array.findIndex()
let topics = [{
id: 1,
name: 'Topic 1',
children: [{
id: 1,name: 'Subtopic 1.2'
}, {
id: 4,name: 'Subtopic 1.4'
}, {
id: 2, name: 'Subtopic 1.1'
}]
}];
const findIndexOf = val => {
return topics[0].children.findIndex(e => e.name.trim() === val.trim())
}
console.log(findIndexOf('Subtopic 1.1'))
No.
You would iterate through children, then have a nested loop iterating through each index value. If you find a match, the incrementing variable from the parent loop is the index you want.
edit: code example
let topics = [
{
id: 1,
name: 'Topic 1',
children: [
{
id: 2,
name: 'Subtopic 1.1'
},
{
id: 2,
name: 'Subtopic 3.1'
},
{
id: 2,
name: 'Subtopic 1.1'
},
{
id: 2,
name: 'Subtopic 2.1'
},
{
id: 2,
name: 'Subtopic 1.1'
}
]
}
];
for (let i in topics[0]["children"]) {
if (topics[0]["children"][i]["name"] == "Subtopic 1.1") {
console.log(i)
}
}

what is wrong in the array map iteration

The Below code, not returning a flat array, is highly confusing, Need a flat array of deeply nested array of objects
have attached jsfiddle link https://jsfiddle.net/k6swuvox/
const arr = [{
id: 1,
name: 'XYZ 1'
}, {
id: 2,
name: 'XYZ 2',
children: [{
id: 5,
name: 'XYZ 5'
}, {
id: 6,
name: 'XYZ 6',
age: 29,
children: [{
id: 7,
name: 'XYZ 7'
}, {
id: 8,
name: 'XYZ 8'
}]
}]
}, {
id: 3,
name: 'XYZ 3'
}, {
id: 4,
name: 'XYZ 4'
}]
const flats = data => data.map(e => {
if (e.children) {
return [...flats(e.children), e]
} else {
console.log("E", e);
return e
}
})
console.log(flats(arr));
With your current code, you will sometimes return an array from the callback:
return [...flats(e.children),e]
and you'll sometimes return a plain object:
else {console.log("E",e);return e }
so the result will be a mix of arrays and plain objects, instead of an array of only objects.
Use flatMap instead, which will implement the flattening you're looking for for you. You'll also need to remove the .children property from items with children before returning them.
const arr=[{id:1,name:"XYZ 1"},{id:2,name:"XYZ 2",children:[{id:5,name:"XYZ 5"},{id:6,name:"XYZ 6",age:29,children:[{id:7,name:"XYZ 7"},{id:8,name:"XYZ 8"}]}]},{id:3,name:"XYZ 3"},{id:4,name:"XYZ 4"}];
const flats = data => data.flatMap(e=>{
const { children, ...objWithoutChildren } = e;
return children
? [...flats(children), objWithoutChildren]
: e;
});
console.log(flats(arr));
Here is an iterative solution using object-scan
// const objectScan = require('object-scan');
const arr = [{ id: 1, name: 'XYZ 1' }, { id: 2, name: 'XYZ 2', children: [{ id: 5, name: 'XYZ 5' }, { id: 6, name: 'XYZ 6', age: 29, children: [{ id: 7, name: 'XYZ 7' }, { id: 8, name: 'XYZ 8' }] }] }, { id: 3, name: 'XYZ 3' }, { id: 4, name: 'XYZ 4' }];
const flatten = objectScan(['**(^children$).id'], {
useArraySelector: false,
rtn: 'parent',
reverse: false,
afterFn: (state) => {
state.result = state.result.map(({ id, name }) => ({ id, name }));
}
});
console.log(flatten(arr));
// => [ { id: 1, name: 'XYZ 1' }, { id: 2, name: 'XYZ 2' }, { id: 5, name: 'XYZ 5' }, { id: 6, name: 'XYZ 6' }, { id: 7, name: 'XYZ 7' }, { id: 8, name: 'XYZ 8' }, { id: 3, name: 'XYZ 3' }, { id: 4, name: 'XYZ 4' } ]
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan#15.0.0"></script>
Disclaimer: I'm the author of object-scan
Need a flat array of deeply nested array of objects
In that case, I'd prefer recursive to get the flexible and high deep level array.
const arr = [{id:1,name:'XYZ 1'},{id:2,name:'XYZ 2',children:[{id:5,name:'XYZ 5'},{id:6,name:'XYZ 6',age:29,children:[{id:7,name:'XYZ 7'},{id:8,name:'XYZ 8'}]}]},{id:3,name:'XYZ 3'},{id:4,name:'XYZ 4'}];
const recursive = (array) => array.reduce((acc, {children = [], ...others}) => {
acc.push(others);
if(children.length > 0) // Base recurisve here.
acc = acc.concat(recursive(children));
return acc;
}, []);
console.log(recursive(arr));
==> As a result, the content structure will make sure like this

Categories