I have an array:
let array = [{id: 1, name:'a'}, {id: 2, name: 'b'},{id: 1, name:'c'}];
I want an array like
arr2 = [[{id: 1, name:'a'}, {id: 1, name:'c'}], [{id: 2, name: 'b'}]]
I tried this but I cant find which array to add to:
$scope.journalsArray = response.data.body.Data;
$scope.newArray = [];
let idsArray = [];
for (let i = 0; i < $scope.journalsArray.length; i++) {
if(idsArray.indexOf($scope.journalsArray[i].journal_id) != -1){
$scope.newArray.push($scope.journalsArray[i]);
}else{
$scope.idsArray.push($scope.journalsArray[i].journal_id);
}
}
Array.reduce over your original array.
If a group exists that has an item with the same id, push into it.
Otherwise create the group.
let array = [{id: 1, name:'a'}, {id: 2, name: 'b'},{id: 1, name:'c'}]
let result = array.reduce((acc, item) => {
const group = acc.find(group => group.find(inner => inner.id === item.id))
if (group)
group.push(item)
else
acc.push([item])
return acc
}, [])
console.log(result)
Using reduce(), find() and filter() methods we can achieve this
let array = [
{id: 1, name:'a'},
{id: 2, name: 'b'},
{id: 1, name:'c'}
];
const results = arr => {
return arr.reduce((result, item ) => {
if (!result.find(obj => obj[0].id === item.id)) {
result.push(array.filter(val => val.id == item.id))
}
return result;
}, [])
}
console.log(results(array));
// [ [ { id: 1, name: 'a' }, { id: 1, name: 'c' } ], [ { id: 2, name: 'b' } ] ]
You could take a Map and collect the objects in the same group. Then get the values of each group as result.
var array = [{ id: 1, name:'a' }, { id: 2, name: 'b' },{ id: 1, name:'c' }],
result = Array.from(
array
.reduce((m, o) => m.set(o.id, [...(m.get(o.id) || []), o]), new Map)
.values()
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Using Array#reduce, Map, destructuring and Array#concat.
const data = [{id: 1, name:'a'}, {id: 2, name: 'b'},{id: 1, name:'c'}];
const res = data.reduce((a,{id,name})=>{
return a.set(id, [{id,name}].concat(a.get(id)||[]));
}, new Map()).values();
console.log([...res]);
let array = [{id: 1, name:'a'}, {id: 2, name: 'b'},{id: 1, name:'c'}]
let result = array.reduce((acc, item) => {
const group = acc.find(group => group.find(inner => inner.id === item.id))
if (group)
group.push(item)
else
acc.push([item])
return acc
}, [])
console.log(result)
let array = [{id: 1, name:'a'}, {id: 2, name: 'b'},{id: 1, name:'c'}]
let result = array.reduce((acc, item) => {
const group = acc.find(group => group.find(inner => inner.id === item.id))
if (group)
group.push(item)
else
acc.push([item])
return acc
}, [])
console.log(result)
Related
How do I solve this while using include()?
const allowedIds = [1, 3]
const allBoats = [{
id: 1,
name: 'titanic'
}, {
id: 2,
name: 'anna'
}, {
id: 3,
name: 'boaty McBoatface'
}, ]
const expectedResult = ['boaty McBoatface', 'titanic']
Consider making allowedIds a Set and then using has, which is O(1), rather than includes on an Array, which is O(N):
const allowedIds = new Set([1, 3]);
const allBoats = [
{
id: 1,
name: "titanic",
},
{
id: 2,
name: "anna",
},
{
id: 3,
name: "boaty McBoatface",
},
];
const allowedBoats = allBoats.filter(b => allowedIds.has(b.id))
.map(b => b.name)
.sort();
console.log(allowedBoats);
Other potentially useful documentation links:
Array.prototype.filter()
Array.prototype.map()
Array.prototype.sort()
const allowedIds = [1, 3]
const allBoats = [{
id: 1,
name: 'titanic'
}, {
id: 2,
name: 'anna'
}, {
id: 3,
name: 'boaty McBoatface'
}, ]
const result = allBoats
.filter(b => allowedIds.includes(b.id))
.map(b => b.name)
.sort((a, b) => a.localeCompare(b))
console.log('result', result)
You can try this as well
allBoats.filter(entry => allowedIds.includes(entry.id)).map(item => item.name).sort()
const allowedIds = [1, 3]
const allBoats = [
{
id: 1,
name: 'titanic'
},
{
id: 2,
name: 'anna'
},
{
id: 3,
name: 'boaty McBoatface'
}
]
const expectedResult = allBoats.reduce((p, c) => allowedIds.includes(c.id) ? p.concat(c.name) : p, []).sort((a, b) => a.localeCompare(b));
console.log(expectedResult);
if you want only those with id 1 or 3:
const selections = allBoats.filter((val)=>{return val.id === 1 || val.id ===3});
const result = selections.map((val,key)=>{ val.name}).sort()
console.log(result) //gives ["boaty McBoatface", "titanic"]
I've tried modifying some of the similar solutions on here but I keep getting stuck, I believe I have part of this figured out however, the main caveat is that:
Some of the objects have extra keys, which renders my object comparison logic useless.
I am trying to compare two arrays of objects. One array is the original array, and the other array contains the items I want deleted from the original array. However there's one extra issue in that the second array contains extra keys, so my comparison logic doesn't work.
An example would make this easier, let's say I have the following two arrays:
const originalArray = [{id: 1, name: "darnell"}, {id: 2, name: "funboi"},
{id: 3, name: "jackson5"}, {id: 4, name: "zelensky"}];
const itemsToBeRemoved = [{id: 2, name: "funboi", extraProperty: "something"},
{id: 4, name: "zelensky", extraProperty: "somethingelse"}];
after running the logic, my final output should be this array:
[{id: 1, name: "darnell"}, {id: 3, name: "jackson5"}]
And here's the current code / logic that I have, which compares but doesn't handle the extra keys. How should I handle this? Thank you in advance.
const prepareArray = (arr) => {
return arr.map((el) => {
if (typeof el === "object" && el !== null) {
return JSON.stringify(el);
} else {
return el;
}
});
};
const convertJSON = (arr) => {
return arr.map((el) => {
return JSON.parse(el);
});
};
const compareArrays = (arr1, arr2) => {
const currentArray = [...prepareArray(arr1)];
const deletedItems = [...prepareArray(arr2)];
const compared = currentArray.filter((el) => deletedItems.indexOf(el) === -1);
return convertJSON(compared);
};
How about using filter and some? You can extend the filter condition on select properties using &&.
const originalArray = [
{ id: 1, name: 'darnell' },
{ id: 2, name: 'funboi' },
{ id: 3, name: 'jackson5' },
{ id: 4, name: 'zelensky' },
];
const itemsToBeRemoved = [
{ id: 2, name: 'funboi', extraProperty: 'something' },
{ id: 4, name: 'zelensky', extraProperty: 'somethingelse' },
];
console.log(
originalArray.filter(item => !itemsToBeRemoved.some(itemToBeRemoved => itemToBeRemoved.id === item.id))
)
Or you can generalise it as well.
const originalArray = [
{ id: 1, name: 'darnell' },
{ id: 2, name: 'funboi' },
{ id: 3, name: 'jackson5' },
{ id: 4, name: 'zelensky' },
];
const itemsToBeRemoved = [
{ id: 2, name: 'funboi', extraProperty: 'something' },
{ id: 4, name: 'zelensky', extraProperty: 'somethingelse' },
];
function filterIfSubset(originalArray, itemsToBeRemoved) {
const filteredArray = [];
for (let i = 0; i < originalArray.length; i++) {
let isSubset = false;
for (let j = 0; j < itemsToBeRemoved.length; j++) {
// check if whole object is a subset of the object in itemsToBeRemoved
if (Object.keys(originalArray[i]).every(key => originalArray[i][key] === itemsToBeRemoved[j][key])) {
isSubset = true;
}
}
if (!isSubset) {
filteredArray.push(originalArray[i]);
}
}
return filteredArray;
}
console.log(filterIfSubset(originalArray, itemsToBeRemoved));
Another simpler variation of the second approach:
const originalArray = [
{ id: 1, name: 'darnell' },
{ id: 2, name: 'funboi' },
{ id: 3, name: 'jackson5' },
{ id: 4, name: 'zelensky' },
];
const itemsToBeRemoved = [
{ id: 2, name: 'funboi', extraProperty: 'something' },
{ id: 4, name: 'zelensky', extraProperty: 'somethingelse' },
];
const removeSubsetObjectsIfExists = (originalArray, itemsToBeRemoved) => {
return originalArray.filter(item => {
const isSubset = itemsToBeRemoved.some(itemToBeRemoved => {
return Object.keys(item).every(key => {
return item[key] === itemToBeRemoved[key];
});
});
return !isSubset;
});
}
console.log(removeSubsetObjectsIfExists(originalArray, itemsToBeRemoved));
The example below is a reusable function, the third parameter is the key to which you compare values from both arrays.
Details are commented in example
const arr=[{id:1,name:"darnell"},{id:2,name:"funboi"},{id:3,name:"jackson5"},{id:4,name:"zelensky"}],del=[{id:2,name:"funboi",extraProperty:"something"},{id:4,name:"zelensky",extraProperty:"somethingelse"}];
/** Compare arrayA vs. delArray by a given key's value.
--- ex. key = 'id'
**/
function deleteByKey(arrayA, delArray, key) {
/* Get an array of only the values of the given key from delArray
--- ex. delList = [1, 2, 3, 4]
*/
const delList = delArray.map(obj => obj[key]);
/* On every object of arrayA compare delList values vs
current object's key's value
--- ex. current obj[id] = 2
--- [1, 2, 3, 4].includes(obj[id])
Any match returns an empty array and non-matches are returned
in it's own array.
--- ex. ? [] : [obj]
The final return is a flattened array of the non-matching objects
*/
return arrayA.flatMap(obj => delList.includes(obj[key]) ? [] : [obj]);
};
console.log(deleteByKey(arr, del, 'id'));
let ff = [{ id: 1, name: 'darnell' }, { id: 2, name: 'funboi' },
{ id: 3, name: 'jackson5' },
{ id: 4, name: 'zelensky' }]
let cc = [{ id: 2, name: 'funboi', extraProperty: 'something' },
{ id: 4, name: 'zelensky', extraProperty: 'somethingelse' }]
let ar = []
let out = []
const result = ff.filter(function(i){
ar.push(i.id)
cc.forEach(function(k){
out.push(k.id)
})
if(!out.includes(i.id)){
// console.log(i.id, i)
return i
}
})
console.log(result)
let selectedRow = ["1","2","3"];
let arr = [
{ id:1, name:"eddie" },
{ id:2, name:"jake" },
{ id:3, name:"susan" },
];
Updation on the answer provided by Andy, If you don't want to update the exiting array and want to result in a new array
let selectedRow = ["1", "2"];
let arr = [
{ id: 1, name: "eddie" },
{ id: 2, name: "jake" },
{ id: 3, name: "susan" },
];
const result = arr.filter(item => !selectedRow.includes(item.id.toString()))
console.log(result)
If you want changes in a current array and don't want to store results in a new array (Not the most efficient solution though)
let selectedRow = ["1", "2"];
let arr = [
{ id: 1, name: "eddie" },
{ id: 2, name: "jake" },
{ id: 3, name: "susan" },
];
for (const row of selectedRow) {
const index = arr.findIndex(item => item.id.toString() === row)
if (index !== -1)
arr.splice(index, 1)
}
console.log(arr)
Make sure your selectedRow array is an array of numbers (because your object ids are numbers).
filter over the array of objects and only keep the ones that selectedRow doesn't include.
const arr = [{ id: 1, name: 'eddie' }, { id: 2, name: 'jake' }, { id: 3, name: 'susan' }];
const selectedRow = ['1', '2'].map(Number);
const result = arr.filter(obj => {
return !selectedRow.includes(obj.id);
});
console.log(result);
Given an array of objects arr1 how can I filter out to a new array the objects that do not have a property equal to any value in the array of numbers arr2
const arr1 = [
{
key: 1,
name: 'Al'
},
{
key: 2,
name: 'Lo'
},
{
key: 3,
name: 'Ye'
}
];
const arr2 = [2, 3]
// Failed attempt
const newArr = arr1.filter(obj1 => arr2.some(num1 => num1 !== obj1.key))
console.log(newArr)
// Expected: [{ key: 1, name: 'Al' }]
// Received: [
// { key: 1, name: 'Al' },
// { key: 2, name: 'Lo' },
// { key: 3, name: 'Ye' }
// ]
Using your syntax:
You have to match on the somein case it's the same and not different. Then if it matches, do not keep the value.
const arr1 = [
{
key: 1,
name: 'Al',
},
{
key: 2,
name: 'Lo',
},
{
key: 3,
name: 'Ye',
},
];
const arr2 = [2, 3];
const newArr= arr1.filter(x => !arr2.some(y => y === x.key));
console.log(newArr);
Alternative syntax below :
const arr1 = [{
key: 1,
name: 'Al',
},
{
key: 2,
name: 'Lo',
},
{
key: 3,
name: 'Ye',
},
];
const arr2 = [2, 3];
const newArr = arr1.filter(({
key,
}) => !arr2.some(y => y === key));
console.log(newArr);
That said, you should be using Array.includes() like some ppl answered. It's simplier for the same outcome
const arr1 = [{
key: 1,
name: 'Al',
},
{
key: 2,
name: 'Lo',
},
{
key: 3,
name: 'Ye',
},
];
const arr2 = [2, 3];
const newArr = arr1.filter(({
key,
}) => !arr2.includes(key));
console.log(newArr);
You can do this
const newArr = arr1.filter(obj => !arr2.includes(obj.key));
This will work for you:
const arr1 = [
{
key: 1,
name: 'Al'
},
{
key: 2,
name: 'Lo'
},
{
key: 3,
name: 'Ye'
}
];
const arr2 = [2, 3]
const filtered = arr1.filter(val => !arr2.includes(val.key))
console.log(filtered)
:)
For situations like this Set is also very cool (and for big arrays more performant):
const arr1 = [
{
key: 1,
name: 'Al'
},
{
key: 2,
name: 'Lo'
},
{
key: 3,
name: 'Ye'
}
];
const arr2 = [2, 3]
const arr2Set = new Set(arr2);
const newArr = arr1.filter(obj1 => !arr2Set.has(obj1.key))
console.log(newArr)
You can use indexOf like this:
const newArr = arr1.filter(obj => arr2.indexOf(obj.key) > -1);
You need to filter the arr1 when arr1 element does not exist in arr2, so I think it could be better to use indexOf() like this
const newArr = arr1.filter(obj1 => arr2.indexOf(obj1.key) === -1)
if the element does not exist in arr2 it will return -1 which what you need.
I just learned a new trick to find the same object in 2 array object, it works very well. it uses array.filter and array.some, as code bellow, but I don't understand how filter() can run when some() will return true or false.
const similarity = (arr, values) => arr.filter(item => values.some(m => (m.id === item.id) && (m.name === item.name)));
my input:
let arr1 = [
{
id: 1,
name: "kiet"
},
{
id: 2,
name: 'phan'
},
{
id: 3,
name: 'tuan'
}]
let arr2 = [
{
id: 1,
name: "kiet"
},
{
id: 2,
name: 'haha'
},
{
id: 5,
name: 'tuan'
}
]
my result :
[ { id: 1, name: 'kiet' } ]
You are Filtering the array, then passing this condition inside the some
(m.id === item.id) && (m.name === item.name)
If the id of the second array (here, m is the second array's objects) is equal to the first array's id (here, item is the array's objects) and the name is equal to the first array's name property. If yes then it will return true. So the filter gets a true and if is does, it will return that particular object for which it gets a true
let arr1 = [{ id: 1, name: "kiet" }, { id: 2, name: 'phan' }, { id: 3, name: 'tuan'}]
let arr2 = [ { id: 1, name: "kiet" }, { id: 2, name: 'haha' }, { id: 5, name: 'tuan' } ]
const similarity = (arr, values) => arr.filter(item => values.some(m => (m.id === item.id) && (m.name === item.name)));
console.log(similarity(arr1,arr2))
You get the elements from the array which have the same properties id/name as the values array.
Array#filter needs a (kind of) boolean value and if true or truthy, then the item is taken to the new array.
Array#some checks an item and if the callback returns a truthy value, then it returns true, if not then false.
const
similarity = (array, values) => array.filter(item => values.some(m => m.id === item.id && m.name === item.name)),
arr1 = [ { id: 1, name: "kiet" }, { id: 2, name: 'phan' }, { id: 3, name: 'tuan' }],
arr2 = [ { id: 1, name: "kiet" }, { id: 2, name: 'haha' }, { id: 5, name: 'tuan' }],
result = similarity(arr1, arr2);
console.log(result);
For larger data sets, you could take a Set, this is iterated once with a combined value and checked against for filtering.
const
similarity = (array, values) => {
const
getKey = ({ id, name }) => [id, name].join('|'),
keys = new Set(values.map(getKey));
return array.filter(o => keys.has(getKey(o)));
},
arr1 = [ { id: 1, name: "kiet" }, { id: 2, name: 'phan' }, { id: 3, name: 'tuan' }],
arr2 = [ { id: 1, name: "kiet" }, { id: 2, name: 'haha' }, { id: 5, name: 'tuan' }],
result = similarity(arr1, arr2);
console.log(result);
This is a good technique if you want to check for array intersection.
const vowels = [...'AEIOU'];
const isVowel = x => vowels.some(v => v === x);
const hasVowel = string => [...string].filter(isVowel).length > 0;