Compare values in 2 object arrays and create new array, js - javascript

I have 2 arrays:
blockedNumbers: ['123', '456', '789', '247'];
contacts: [
{name: 'Foo', numbers: [{ home:'123' }, { mobile:'456' }]},
{name: 'Bar', numbers: [{ home:'789' }]}
]
I want to create a new array of blocked contacts which will contain:
[
{ name: Foo, numbers: [{ home:'123' }, { mobile:'456' }] },
{name: 'Bar', numbers: [{ home:'789' }]}
'247'
]
So the solution I have tried first loops over blocked numbers, then forEach contact, if blocked number in numbers, push to array. But the result turns out as
[
'123'
{ name: Foo, numbers: ['123', '456'] },
{name: 'Bar', numbers: ['789']}
'456'
'789'
'247'
]
Code below:
const newBlacklistWithContacts = [];
blockedNumbers.forEach((blockedNumber) => {
contacts.map((contact) => {
// if blocked number in contacts
Object.keys(contact.numbers).forEach((e) => {
if (contact.numbers[e] === blockedNumber) {
const alreadyAdded = newBlacklistWithContacts.find(blacklistContact => blacklistContact.name === contact.name);
if (!alreadyAdded) {
return newBlacklistWithContacts.push({ name: contact.name, numbers: contact.numbers });
}
}
else if (!newBlacklistWithContacts.includes(blockedNumber)) {
return newBlacklistWithContacts.push(blockedNumber);
}
});
});
});
I'm sure there is a more efficient way to do this & actually return what I need? (All of the blacklisted contacts and if not in contacts, only the number) I am using js and React.js in this project

If your data set is really large, you can optimise your algorithm by doing O(1) lookups in a Set instead of using indexOf or includes which do O(n) lookups:
// Input
const blockedNumbers = ['123', '456', '789', '247'];
const contacts = [{name: 'Foo', numbers: [{ home:'123' }, { mobile:'456' }]}, {name: 'Bar', numbers: [{ home:'789' }]}];
// Algorithm
const set = new Set(blockedNumbers);
const notused = new Set(blockedNumbers);
const newBlacklistWithContacts = contacts.filter(contact =>
contact.numbers.map(obj => Object.values(obj)[0])
.filter(number => set.has(number) && (notused.delete(number) || true)).length
).concat(...notused);
// Output
console.log(newBlacklistWithContacts);
.as-console-wrapper { max-height: 100% !important; top: 0; }

var blockedNumbers = ['123', '456', '789', '247'];
var contacts = [{
name: 'Foo',
numbers: [{
home: '123'
}, {
mobile: '456'
}]
},
{
name: 'Bar',
numbers: [{
home: '789'
}]
}
]
var blocks = [];
contacts.forEach(v1 => (v1.numbers.forEach(v2 => {
blocks.push(Object.values(v2)[0]);
})));
blockedNumbers.forEach(val => (blocks.indexOf(val) == -1 ? contacts.push(val) : null));
console.log(contacts);

Related

How to remove data with same id in an array of object using javascript?

in an arry of objects i want to remove object which have same id (duplicated data) using javascript.
below is the input array
const input = [
{
id: '1',
name: 'first',
},
{
id: '1',
name: 'first',
},
{
id: '2',
name: 'second',
},
{
id: '2',
name: 'second',
},
]
so as you see from above array there are duplicating data with id '1' and '2'.
if there is similar id i want include only one
so the expected output is like below,
const output = [
{
id: '1',
name: 'first',
},
{
id: '2',
name: 'second',
},
]
how can i do this. could someone help me with this. i am new to programming thanks.
You can use reduce to filter data from the array based on some condition like bellow
const input = [
{
id: '1',
name: 'first',
},
{
id: '1',
name: 'first',
},
{
id: '2',
name: 'second',
},
{
id: '2',
name: 'second',
},
]
const result = input.reduce((accumulator, current) => {
let exists = accumulator.find(item => {
return item.id === current.id;
});
if(!exists) {
accumulator = accumulator.concat(current);
}
return accumulator;
}, []);
console.log(result);
Similar to this answer. You will have to change the const to let while declaring input though, or use a new variable I suppose.
filtered_input = input.filter((value, index, self) =>
index === self.findIndex((t) => (
t.id === value.id
))
)
There is a lot of good approachs here.
Here is my approach for removing matching property from the original array and sending it back in the return if found.
I prefer to use this one, if you are looping through a external array and matching them, this way you dont need to loop through the whole array again and again for each, because while you are finding the matches it keeps removing them from the original array, increasing performance.
Note that this will return the first match found
let id = "601985b485d9281d64056953"
let contacts = [{
...,
parent: "601985b485d9281d64056953",
...,
},
{
...,
parent: "601985b485d9281d64065128",
...,
}
]
function findAndRemoveObjectFromArray(array, internalProperty, externalProperty, convertType = "string", returnObject = false) {
let objIndex = -1
if (convertType === "string") objIndex = array.findIndex((obj) => String(obj[`${internalProperty}`]) === String(externalProperty));
if (convertType === "number") objIndex = array.findIndex((obj) => Number(obj[`${internalProperty}`]) === Number(externalProperty));
if (objIndex > -1) {
const object = array.splice(objIndex, 1);
if (returnObject) return object.shift()
return object
}
return [];
}
let currentContact = findAndRemoveObjectFromArray(contacts, "parent", id, 'string', true)
// Results:{..., parent: "601985b485d9281d64056953",...}
you could use Set to get rid of the duplicate data like this
const input = [
{
id: '1',
name: 'first',
},
{
id: '1',
name: 'first',
},
{
id: '2',
name: 'second',
},
{
id: '2',
name: 'second',
},
]
const result = [...new Set(input.map(JSON.stringify))].map(JSON.parse)
console.log(result)
Below is another approach
const input = [
{
id: '1',
name: 'first',
},
{
id: '1',
name: 'first',
},
{
id: '2',
name: 'second',
},
{
id: '2',
name: 'second',
},
];
const uniqueIds = new Set();
const uniqueList = input.filter(element => {
const isDuplicate = uniqueIds.has(element.id);
uniqueIds.add(element.id);
return !isDuplicate;
});
console.log(uniqueList);

How to splice multiple values from array of objects which matches given nested array

I am trying to remove the array of objects if the given array of objects matches with the index but it is only removing the last index value.
How we can remove multiple values?
let idArr = [[{ index: 2 }], [{ index: 3 }]];
let obj = [
{
id: 1,
name: 'abc',
},
{
id: 2,
name: 'abc',
},
{
id: 3,
name: 'abc',
},
{
id: 4,
name: 'abc',
},
];
let data = obj.filter((item, i) =>
idArr.reduce((val) => val.find(({ index }) => i === index))
);
//expected output
[
{
id: 1,
name: 'abc',
},
{
id: 2,
name: 'abc',
},
];
I think that following code achieves what you're expecting
let data = obj.filter((obj, idx) => !idArr.find(id => id[0].index === idx));

Lodash group by specific words/prefix in a key

I wonder how I can group this array based on the prefix text in name key (split the name key at the : colon) using Lodash.
const tags = [
{ name: 'Animals: Frogs', id: 1 },
{ name: 'Animals: Lions', id: 2 },
{ name: 'Birds: Crows', id: 3 }
];
to
const tags = [{
animals: [
{ name: 'Frogs', id: 1 },
{ name: 'Lions', id: 2 },
],
birds: [
{ name: 'Crows', id: 3}
]
}];
Does Lodash have any functions to handle this, or is a custom function/regex needed?
If the pure JS suffices, it can be done this way (the result is an object here, not an array, but this can be changed if needed):
const tags = [
{ name: 'Animals: Frogs', id: 1 },
{ name: 'Animals: Lions', id: 2 },
{ name: 'Birds: Crows', id: 3 }
];
const tags2 = tags.reduce(
(acc, { name, id }) => {
let [group, type] = name.split(': ');
group = group.toLowerCase();
acc[group] ??= [];
acc[group].push({ name: type, id });
return acc;
},
{},
);
console.log(tags2);

Accessing nested array in a json

let ages = data
.filter(isDog)
.map(dogYears)
.reduce(sum);
mL/hr
i want to find the best way of accessing array elements in a javascript object.
Eg: I want to find the first faculty name & first specializations for each course.
var students =
{
deptartment:[
{
name:'Computer Science',
age:20,
Course:[
{ id: 100000
name:'Object Oriented Programming',
faculty:[
{
id:123,
name:'John',
Specialization: [
{name: 'science'},
{name: 'Physics'}
]
}
]
},
{ id: 100001
name:'C#',
faculty:[
{
id:124,
name:'Denis',
Specialization: [
{name: 'Ecnonomics'},
{name: 'Physics'}
]
}
]
}
],
}
]
};
I know i can get the faculty name and specialization by
var courses= deptartment && deptartment.Course ;
var facultyWithSpecialization= {};
if(courses){
courses.forEach(course =>{
var fname = course.faculty && course.faculty[0].name;
var s= course.faculty && course.faculty.Specialization;
facultyWithSpecialization[fname] = s && s[0].name;
})
}
use Object.assign({}, deptartment.Course) instead of department.Course
tried to use the below code but it doesn't make much difference.
var courses=Object.values(Object.assign({}, deptartment.Course));
var fname = Object.values(Object.assign({}, course.faculty[0].Specialization[0]));
Expecting
'John': 'science'
'Denis': 'Ecnonomics'
You can try this. There were many error in the object including spelling mistakes and formatting
var students = {
deptartment: [{
name: 'Computer Science',
age: 20,
Course: [{
id: 100000,
name: 'Object Oriented Programming',
faculty: [{
id: 123,
name: 'John',
Specialization: [{
name: 'science'
},
{
name: 'Physics'
}
]
},
{
id: 124,
name: 'Denis',
Specialization: [{
name: 'Ecnonomics'
},
{
name: 'Physics'
}
]
}
]
}],
}]
}
var obj = {};
students.deptartment.forEach((e) => {
e.Course.forEach((k) => {
k.faculty.forEach((l) => {
obj[l.name] = l.Specialization[0].name
})
})
})
console.log(obj)
I think you meant department instead of deptartment.
I modified a bit your JSON as it was a bit buggy:
var students = {
departments:[
{
name:'Computer Science',
age:20,
Courses:[
{ id: 100000,
name:'Object Oriented Programming',
faculty:[
{
id:123,
name:'John',
Specialization: [
{name: 'science'},
{name: 'Physics'}
]
},
{
id:124,
name:'Denis',
Specialization: [
{name: 'Ecnonomics'},
{name: 'Physics'}
]
}
]
}
],
}]
}
You can use map to achieve this nesting:
students.departments.map(
department => department.Courses.map(
course => course.faculty.map(
student => ({
name: student.name,
specialization: student.Specialization[0].name // check nulls here!
})
)
)
)

flatten an array of objects in javascript

I have a data structure that looks like this
const array = [{
name: 'bar',
children: [{
name: 'foo',
children: [{
name: 'baz123',
}, {
name: 'baz',
}]
}]
}, {
name: 'shallowKey'
}, {
name: 'abc'
}];
And I would like to flatten it to look something like this
[{
name: 'bar'
}, {
name: 'foo',
}, {
name: 'baz123',
}, {
name: 'baz',
}, {
name: 'shallowKey'
}, {
name: 'abc'
}];
I tried lodash like this https://jsfiddle.net/hmzhjji/081q60qg/1/
But it's not doing anything, any other way I can do this?
Thanks
A recursive way would be:
function flatten(array, result = []){
for(const {name, children} of array){
result.push({name});
if(children) flatten(children, result);
}
return result;
}
Or the alternative ES6 version:
const flatten = array => array.reduce((res, {name, children = []}) => res.concat(name).concat(flatten(children)), []);
So you can do flatten(array) to get the desired result.
You can use forEach to iterate over the array and check if the required object is present and call the function recursively
const array = [{
name: 'bar',
children: [{
name: 'foo',
children: [{
name: 'baz123',
}, {
name: 'baz',
}]
}]
}, {
name: 'shallowKey'
}, {
name: 'abc'
}];
var res = [];
function flatten(array){
array.forEach(function(obj){
var name = {name: obj.name}
res.push(name);
if(obj.children){
flatten(obj.children)
}
})
return res;
}
console.log(flatten(array))

Categories