Remove object value in array if it doesn't exist - javascript

I have an array of objects as follows
const array = [
{id:1,parentIds:[]}
{id:2,parentIds:[1,3]}
{id:3,parentIds:[1,2,4]}
]
How can I make it possible to remove an object's parentIds value if it doesn't exist in the array? to look something like this
const array = [
{id:1,parentIds:[]}
{id:2,parentIds:[1,3]}
{id:3,parentIds:[1,2]}
]

You can try this solution:
const array = [{
id: 1,
parentIds: []
}, {
id: 2,
parentIds: [1, 3]
}, {
id: 3,
parentIds: [1, 2, 4]
}];
const idsArr = new Set(array.map(el => el.id));
array.forEach(el => {
el.parentIds = el.parentIds.filter(el => idsArr.has(el));
})
console.log(array);

It's better to avoid mutating the original array parentIds, use immutation to create new array:
const array = [
{id:1,parentIds:[]},
{id:2,parentIds:[1,3]},
{id:3,parentIds:[1,2,4]}
]
const ids = array.map(({id}) => id)
const newArray = array.map(({parentIds,...arrayItemRest}) => {
const newparentIds = parentIds.filter(id => ids.includes(id))
return {
...arrayItemRest,
parentIds: newparentIds
}
})

const array = [
{id:1,parentIds:[]},
{id:2,parentIds:[1,3]},
{id:3,parentIds:[1,2,4]}
]
// Let's create an array only containing the ids
var ids = array.map(o => o.id)
// Loop array
array.forEach((object) => {
// Loop all parent ids
object.parentIds.forEach((id, index) => {
// Check if we find the id in our list
if (ids.indexOf(id) === -1) {
// Delete item from array if not found
object.parentIds.splice(index, 1)
}
})
})
// The result
console.log(array)

You can map (documentation here) your parent Ids and then filter using the includes method (documentation here)
const array = [{
id: 1,
parentIds: []
},
{
id: 2,
parentIds: [1, 3]
},
{
id: 3,
parentIds: [1, 2, 4]
}
]
const parents = array.map(x => x.id)
array.forEach(item => {
item.parentIds = item.parentIds.filter(x => parents.includes(x))
})
console.log(array)

Get a list of keys/ids using map, and then map over the array of objects to filter out the parentIds that are missing, returning a new array of updated objects.
const data=[{id:1,parentIds:[]},{id:2,parentIds:[1,3]},{id:3,parentIds:[1,2,4]}];
function removeIds(data) {
// Get the ids from all the array objects
const keys = data.map(obj => obj.id);
// `map` over the array and return a new
// array of updated objects
return data.map(obj => {
const newIds = obj.parentIds.filter(id => {
return keys.includes(id);
});
return { ...obj, parentIds: newIds };
});
}
console.log(removeIds(data));

Well basic way would be to go trough array every time there is a change, and update parentIds list.
To do that:
const dummyArray = [
{id:1,parentIds:[]},
{id:2,parentIds:[1,3]},
{id:3,parentIds:[1,2,4]}
];
/* You can do this with regular array, this only ensures that ids are unique */
const idsSet = new Set();
dummyArray.forEach(it => idsSet.add(it.id));
dummyArray.forEach(it => {
/* If you are using array, you would need to loop trough for each id and check if existing */
const newParentIds = it.parentIds.filter(id => idsSet.has(id));
it.parentIds = newParentIds;
console.log(it.parentIds);
});
There would be a better solution for this for sure, so please try to take this as an example for logic which can be used.

const array = [
{ id: 1, parentIds: [] },
{ id: 2, parentIds: [1, 3] },
{ id: 3, parentIds: [1, 2, 4] },
];
const removeParentIds = (array) => {
return array.map((item) => {
const { parentIds } = item;
return {
...item,
parentIds: parentIds.filter((parentId) => array.some((item) => item.id === parentId)),
};
});
}
console.log(removeParentIds(array));

You can add childIds in each object, so when you remove one object you can go through each of child's and remove from it's parents as-well.
const array = [
{id:1,parentIds:[],childIds:[2,3]},
{id:2,parentIds:[1,3],childIds:[3]},
{id:3,parentIds:[1,2],childIds:[2]}
]
function idChecker(id){
for(let i=0; i<array.length;i++) if(array[i].id === id) return i;
return undefined
}
function removeObject(id){
let key = idChecker(id)
if(key === undefined) return false
let children = array[key].childIds
children.map(val => {
let keyOfVal = idChecker(val)
array[keyOfVal].parentIds.splice(array[keyOfVal].parentIds.indexOf(id), 1)
})
array.splice(idChecker(id), 1)
return true
}

Loop through inner parentIds array and remove members that are not any of the outer ids.
const array = [
{ id: 1, parentIds: [] },
{ id: 2, parentIds: [1, 3] },
{ id: 3, parentIds: [1, 2, 4] }
];
array.forEach(
(o) =>
(o.parentIds = o.parentIds.filter((pI) =>
array.map((o) => o.id).includes(pI)
))
);
console.log(array);

Related

How can i compare two arrays of different length and keys on the basis of matching key values?

I have tried this, but it is giving the correct result
Array1
Array1: [
{
id: 2,
city: 'washington',
code: 0099,
room: 5,
...
},
{
...
},
...
]
Array 2
Array2: [
{
"id": 2,
"name": "john"
"number": 727625,
"etage": 5,
"status": 0,
...
},
{
...
},
...
]
My Code
let Result = [];
if (Array1 && Array1.length > 0 && Array2 && Array2.length > 0) {
Array1.forEach((arr1, index) => {
Array2.forEach((arr2, index) =>{
if (arr1.id === arr2.id && arr1.room === arr2.etage) {
Result.push(arr1)
}
})
})
}
console.log(Result)
What I want ?
I want items(objects) of Array1 by comparing both arrays, where
both have same id's && room from Array1's object equal to the etage
from Array2's object.
Please guide me, how can I do this in ES6 style in React js?
The main problem with nested loops is the unnecessary iteration of each element of the first array and multiple iterations of the second array.
This approach takes two loops, one for generating all keys from array2 and the other to filter array1.
You could take a Set for compound key of id and etage and filte the array for getting the items with same id and room.
const
getKey = (...values) => values.join('|'),
keys = new Set(array2.map(({ id, etage }) => getKey(id, etage))),
result = array1.filter(({ id, room }) => keys.has(getKey(id, room));
With condition
room > etage
and a Map.
const
ids = array2.reduce(
(m, { id, etage }) => m.set(id, Math.min(etage, m.get(id) || 0)),
new Map
),
result = array1.filter(({ id, room }) => room > ids.get(id));
I'd do something like this:
Array1= [
{
id: 2,
city: 'washington',
code: 0099,
room: 5,
}
];
Array2= [
{
"id": 2,
"name": "john",
"number": 727625,
"etage": 5,
},
];
const result = Array1.filter(a1 => Array2.find(a2 => a1.id == a2.id) && Array2.find(a2 => a1.room == a2.etage));
console.log(result);
That will return a filtered array by room, etage and id.
You can use filter and some ES6 methods:
const arr1 = [
{
id: 1,
room: 1
},
{
id: 2,
room: 5
},
{
id: 3,
room: 3
}
];
const arr2 = [
{
id: 0,
etage: 0
},
{
id: 2,
etage: 5
},
{
id: 3,
etage: 3
}
];
const getTheSame = (arr1, arr2) => {
return arr1.filter(o1 =>
arr2.some(o2 => o1.id === o2.id && o1.room === o2.etage)
);
};
console.log("Result: ", getTheSame(arr1, arr2));

How to compare two different arrays which has different property names and remove unmatched ones in javascript?

I havve two different arrays with different property names like below
arrayA = [
{ id: 20, name: 'Jason' },
{ id: 15, name: 'Harry' },
{ id: 5, name: 'Clara' },
{ id: 9, name: 'Melonie' }
]
arrayB = [
{ courseID: 12, studentID: 20 },
{ courseID: 12, studentID: 15 }
]
I want to compare these two different arrays and remove unmatched ids from arrayA. For comparison, id field of arrayA and studentID field of arrayB matters. if these fileds aren't equal to each other, they should be removed from arrayA.
Expected is below
arrayA = [{id: 20, name: 'Jason' }, { id: 15, name: 'Harry' }]
Here is what I tried below but didn't work. Gave me empty array.
filteredElements = this.arrayA.map(e => e.id).filter(
val => this.arrayB.indexOf(val.studentID) !== -1
);
You can do that in following steps:
Use map() on arrayB and create array of courseID.
Then create a Set() from that Array
Then use filter() arrayA and check whether id of object exists in above created Set or not using Set.prototype.has()
const arrayA = [{id:20,name:'Jason'},{id:15,name:'Harry'},{id:5,name:'Clara'},{id:9,name:'Melonie'}]
const arrayB =[{courseID:12,studentID:20},{courseID:12,studentID:15}];
const ids = new Set(arrayB.map(x => x.studentID));
const res = arrayA.filter(x => ids.has(x.id));
console.log(res);
let arrayA = [{id: 20,name: 'Jason'},{id: 15,name: 'Harry'},{id: 5,name: 'Clara'},{id: 9,name: 'Melonie'}]
let arrayB = [{courseID: 12,studentID: 20},{courseID: 12,studentID: 15}];
let filtered=arrayA.filter(obj =>{ if(arrayB.find(course => course.studentID == obj.id))return true;return false;
});
console.log(filtered);
Try this:
var studentIds = arrayB.map(course => course.studentID);
var result = arrayA.filter(student => studentIds.includes(student.id));
The variable result contains your result.
Create a dictionary from courseMembers, keyed on studentID, to enable O(1) lookup.
Filter students according to the dictionary.
const students = [{id:20,name:'Jason'},{id:15,name:'Harry'},{id:5,name:'Clara'},{id:9,name:'Melonie'}]
const courseMembers = [{courseID:12,studentID:20},{courseID:12,studentID:15}]
function withCourses(students, courseMembers) {
const map = courseMembers.reduce((acc, {studentID}) =>
(acc[studentID] = true, acc), {})
return students.filter(({id}) => map[id])
}
const result = withCourses(students, courseMembers)
console.log(result) // [{ id:20, name:"Jason" },{ id:15, name:"Harry" }]

How to check an array of objects is totally belongs to another?

There are two array of objects like this
var a = [
{id:'1'},
{id:'2'}
];
var b = [
{id:'1',name:'a'},
{id:'2',name:'b'},
{id:'3',name:'c'}
]
And I need a function, if all ids of the elements of array a can be found in array b, it will return true, otherwise return false
You could use a Set and check with Array#every.
const check = (a, b) => a.every((s => ({ id }) => s.has(id))(new Set(b.map(({ id }) => id))));
var a = [{ id: '1' }, { id: '2' }],
b = [{ id: '1', name: 'a' }, { id: '2', name: 'b' }, { id: '3', name: 'c' }];
console.log(check(a, b));
This is not the most efficient way, as it needs to create the list of ids in b for each item in a.
var a = [
{id:'1'},
{id:'2'},
{id:'7'},
];
var b = [
{id:'1',name:'a'},
{id:'2',name:'b'},
{id:'3',name:'c'}
]
const allPresent = a
.map(item => item.id)
.map(id => Object.assign({
id,
present: b
.map(item => item.id)
.indexOf(id) > -1,
}))
console.log(allPresent)
You can use the following
var a = [
{id:'1'},
{id:'2'}
];
var b = [
{id:'1',name:'a'},
{id:'2',name:'b'},
{id:'3',name:'c'}
]
console.log(checkobject());
function checkobject()
{
var checkid=true;
a.forEach(function(el)
{
var check=b.findIndex(function(element) {
return element.id===el.id;
});
if(check==-1)
{
checkid=false;
return;
}
});
return checkid;
}
Can use this simple way:
var a = [
{id:'1'},
{id:'2'}
];
var b = [
{id:'1',name:'a'},
{id:'2',name:'b'},
{id:'3',name:'c'}
];
var id_a = a.map((current)=>{
return current.id;
}); console.log(id_a); // ["1", "2"]
var id_b = b.map((current)=>{
return current.id;
}); console.log(id_b); // ["1", "2", "3"]
// check if id_a in id_b, check total element of each set
let bool = Array.from(new Set(id_b) ).length == Array.from(new Set(id_b.concat(id_a)) ).length;
console.log(bool);
Solution using Array.prototype.filter and Array.prototype.some:
const includeCheck = (a, b) => {
if (b.filter(el => a.some(obj => obj.id === el.id)).length === b.length) {
console.log('b fully includes a')
} else {
console.log('b does not fully include a')
}
}
let a = [{id:'1'}, {id:'2'}, {id:'3'}],
b = [{id:'1',name:'a'}, {id:'2',name:'b'}, {id:'3',name:'c'}]
includeCheck(a, b);
It compares lengths of original b array and b array filtered by a array's ids to determine whether b has all a ids or not.

Compare array of ints with Array of Objects and return property

Given the following array of objects:
var arrayOfObjs = [{
id: "d8eed6df-9f12-47d4-5b71-3352a92ebcf0",
typeID: 2
},
{
id: "270d8355-d8b6-49c4-48ac-97a44422c705",
typeID: 3
},
{
id: "sdks7878-d8b6-49c4-48ac-97a44422c705",
typeID: 4
}
];
And an Array of Ints:
var arrayOfInts = [2, 4];
How would I compare the two and return an array of IDs if the array of ints matches the arrayOfObjects.
The return should be:
var matchingIDs = [
"d8eed6df-9f12-47d4-5b71-3352a92ebcf0",
"sdks7878-d8b6-49c4-48ac-97a44422c705"
];
var missingIDs = ["270d8355-d8b6-49c4-48ac-97a44422c705"];
Use array.prototype.filter, array.prototype.includes and array.prototype.map
var datas = [{
id: "d8eed6df-9f12-47d4-5b71-3352a92ebcf0",
typeID: 2
},
{
id : "270d8355-d8b6-49c4-48ac-97a44422c705",
typeID: 3
},
{
id : "sdks7878-d8b6-49c4-48ac-97a44422c705",
typeID: 4
}];
var arrayOfInts = [2, 4];
var matchingIDs = datas.filter(d => arrayOfInts.includes(d.typeID)).map(e => e.id);
var missingIDs= datas.filter(d => !arrayOfInts.includes(d.typeID)).map(e => e.id);
console.log('matchingIDs: ', matchingIDs);
console.log('missingIDs: ', missingIDs);
Many ways to accomplish this, I chose map\filter usage since javascript is a functional language.
const allItems = [{
id: "d8eed6df-9f12-47d4-5b71-3352a92ebcf0",
typeID: 2
},
{
id : "270d8355-d8b6-49c4-48ac-97a44422c705",
typeID: 3
},
{
id : "sdks7878-d8b6-49c4-48ac-97a44422c705",
typeID: 4
}];
const validIds = [2, 4];
const filteredItems = allItems
.filter(({typeID})=> validIds.includes(typeID))
.map(({id})=>id)
console.log(filteredItems)
With lodash you can achieve this using a chain with _.keyBy(), _.at(), and _.map():
var arrayOfObjs = [{"id":"d8eed6df-9f12-47d4-5b71-3352a92ebcf0","typeID":2},{"id":"270d8355-d8b6-49c4-48ac-97a44422c705","typeID":3},{"id":"sdks7878-d8b6-49c4-48ac-97a44422c705","typeID":4}];
var arrayOfInts = [2, 4];
var result = _(arrayOfObjs)
.keyBy('typeID') // get a dictionary of objects by their type ids
.at(arrayOfInts) // get the objects that matches the array of ints
.map('id') // map each object to the id
.value();
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>

How to do equivalent of LINQ SelectMany() just in javascript

Unfortunately, I don't have JQuery or Underscore, just pure javascript (IE9 compatible).
I'm wanting the equivalent of SelectMany() from LINQ functionality.
// SelectMany flattens it to just a list of phone numbers.
IEnumerable<PhoneNumber> phoneNumbers = people.SelectMany(p => p.PhoneNumbers);
Can I do it?
EDIT:
Thanks to answers, I got this working:
var petOwners =
[
{
Name: "Higa, Sidney", Pets: ["Scruffy", "Sam"]
},
{
Name: "Ashkenazi, Ronen", Pets: ["Walker", "Sugar"]
},
{
Name: "Price, Vernette", Pets: ["Scratches", "Diesel"]
},
];
function property(key){return function(x){return x[key];}}
function flatten(a,b){return a.concat(b);}
var allPets = petOwners.map(property("Pets")).reduce(flatten,[]);
console.log(petOwners[0].Pets[0]);
console.log(allPets.length); // 6
var allPets2 = petOwners.map(function(p){ return p.Pets; }).reduce(function(a, b){ return a.concat(b); },[]); // all in one line
console.log(allPets2.length); // 6
for a simple select you can use the reduce function of Array.
Lets say you have an array of arrays of numbers:
var arr = [[1,2],[3, 4]];
arr.reduce(function(a, b){ return a.concat(b); }, []);
=> [1,2,3,4]
var arr = [{ name: "name1", phoneNumbers : [5551111, 5552222]},{ name: "name2",phoneNumbers : [5553333] }];
arr.map(function(p){ return p.phoneNumbers; })
.reduce(function(a, b){ return a.concat(b); }, [])
=> [5551111, 5552222, 5553333]
Edit:
since es6 flatMap has been added to the Array prototype.
SelectMany is synonym to flatMap.
The method first maps each element using a mapping function, then flattens the result into a new array.
Its simplified signature in TypeScript is:
function flatMap<A, B>(f: (value: A) => B[]): B[]
In order to achieve the task we just need to flatMap each element to phoneNumbers
arr.flatMap(a => a.phoneNumbers);
As a simpler option Array.prototype.flatMap() or Array.prototype.flat()
const data = [
{id: 1, name: 'Dummy Data1', details: [{id: 1, name: 'Dummy Data1 Details'}, {id: 1, name: 'Dummy Data1 Details2'}]},
{id: 1, name: 'Dummy Data2', details: [{id: 2, name: 'Dummy Data2 Details'}, {id: 1, name: 'Dummy Data2 Details2'}]},
{id: 1, name: 'Dummy Data3', details: [{id: 3, name: 'Dummy Data3 Details'}, {id: 1, name: 'Dummy Data3 Details2'}]},
]
const result = data.flatMap(a => a.details); // or data.map(a => a.details).flat(1);
console.log(result)
For those a while later, understanding javascript but still want a simple Typed SelectMany method in Typescript:
function selectMany<TIn, TOut>(input: TIn[], selectListFn: (t: TIn) => TOut[]): TOut[] {
return input.reduce((out, inx) => {
out.push(...selectListFn(inx));
return out;
}, new Array<TOut>());
}
Sagi is correct in using the concat method to flatten an array. But to get something similar to this example, you would also need a map for the select part
https://msdn.microsoft.com/library/bb534336(v=vs.100).aspx
/* arr is something like this from the example PetOwner[] petOwners =
{ new PetOwner { Name="Higa, Sidney",
Pets = new List<string>{ "Scruffy", "Sam" } },
new PetOwner { Name="Ashkenazi, Ronen",
Pets = new List<string>{ "Walker", "Sugar" } },
new PetOwner { Name="Price, Vernette",
Pets = new List<string>{ "Scratches", "Diesel" } } }; */
function property(key){return function(x){return x[key];}}
function flatten(a,b){return a.concat(b);}
arr.map(property("pets")).reduce(flatten,[])
// you can save this function in a common js file of your project
function selectMany(f){
return function (acc,b) {
return acc.concat(f(b))
}
}
var ex1 = [{items:[1,2]},{items:[4,"asda"]}];
var ex2 = [[1,2,3],[4,5]]
var ex3 = []
var ex4 = [{nodes:["1","v"]}]
Let's start
ex1.reduce(selectMany(x=>x.items),[])
=> [1, 2, 4, "asda"]
ex2.reduce(selectMany(x=>x),[])
=> [1, 2, 3, 4, 5]
ex3.reduce(selectMany(x=> "this will not be called" ),[])
=> []
ex4.reduce(selectMany(x=> x.nodes ),[])
=> ["1", "v"]
NOTE: use valid array (non null) as intitial value in the reduce function
try this (with es6):
Array.prototype.SelectMany = function (keyGetter) {
return this.map(x=>keyGetter(x)).reduce((a, b) => a.concat(b));
}
example array :
var juices=[
{key:"apple",data:[1,2,3]},
{key:"banana",data:[4,5,6]},
{key:"orange",data:[7,8,9]}
]
using :
juices.SelectMany(x=>x.data)
I would do this (avoiding .concat()):
function SelectMany(array) {
var flatten = function(arr, e) {
if (e && e.length)
return e.reduce(flatten, arr);
else
arr.push(e);
return arr;
};
return array.reduce(flatten, []);
}
var nestedArray = [1,2,[3,4,[5,6,7],8],9,10];
console.log(SelectMany(nestedArray)) //[1,2,3,4,5,6,7,8,9,10]
If you don't want to use .reduce():
function SelectMany(array, arr = []) {
for (let item of array) {
if (item && item.length)
arr = SelectMany(item, arr);
else
arr.push(item);
}
return arr;
}
If you want to use .forEach():
function SelectMany(array, arr = []) {
array.forEach(e => {
if (e && e.length)
arr = SelectMany(e, arr);
else
arr.push(e);
});
return arr;
}
Here you go, a rewritten version of joel-harkes' answer in TypeScript as an extension, usable on any array. So you can literally use it like somearray.selectMany(c=>c.someprop). Trans-piled, this is javascript.
declare global {
interface Array<T> {
selectMany<TIn, TOut>(selectListFn: (t: TIn) => TOut[]): TOut[];
}
}
Array.prototype.selectMany = function <TIn, TOut>( selectListFn: (t: TIn) => TOut[]): TOut[] {
return this.reduce((out, inx) => {
out.push(...selectListFn(inx));
return out;
}, new Array<TOut>());
}
export { };
You can try the manipula package that implements all C# LINQ methods and preserves its syntax:
Manipula.from(petOwners).selectMany(x=>x.Pets).toArray()
https://github.com/litichevskiydv/manipula
https://www.npmjs.com/package/manipula
For later versions of JavaScript you can do this:
var petOwners = [
{
Name: 'Higa, Sidney',
Pets: ['Scruffy', 'Sam']
},
{
Name: 'Ashkenazi, Ronen',
Pets: ['Walker', 'Sugar']
},
{
Name: 'Price, Vernette',
Pets: ['Scratches', 'Diesel']
}
];
var arrayOfArrays = petOwners.map(po => po.Pets);
var allPets = [].concat(...arrayOfArrays);
console.log(allPets); // ["Scruffy","Sam","Walker","Sugar","Scratches","Diesel"]
See example StackBlitz.
Exception to reduce and concat methods, you can use the native flatMap api.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flatMap

Categories

Resources