I'm writing some code here to add an element on an array with the following logic
If the element exists on the array, the function should remove the element from the array and return the array without the given element, otherwise it should return the array with the given element appended on it.
Having this in mind, I'm thinking if there's a better way to do this, this is the code I've writed to do this.
function filterArray(arr, obj, key) {
for (let i = 0; i < arr.length; i++) {
if (arr[i][key] === obj[key]) {
const newArr = [...arr]
newArr.splice(i, 1)
return newArr
}
}
return [...arr, obj]
}
const fruits = [
{ id: 1, fruit: "Apple" },
{ id: 2, fruit: "Banana" },
{ id: 3, fruit: "Pineapple" }
]
const removedBanana = filterArray(fruits, {
id: 3,
fruit: "Banana"
}, "fruit")
const addedStrawberry = filterArray(fruits, {
id: 4,
fruit: "Strawberry"
}, "fruit")
console.log(removedBanana) // [ { id: 1, fruit: 'Apple' }, { id: 3, fruit: 'Pineapple' } ]
console.log(addedStrawberry)
// [
// { id: 1, fruit: 'Apple' },
// { id: 2, fruit: 'Banana' },
// { id: 3, fruit: 'Pineapple' },
// { id: 4, fruit: 'Strawberry' }
// ]
I'm writing some code here to add an element on an array with the following logic
If the element exists on the array, the function should remove the element from the array and return the array without the given element, otherwise it should return the array with the given element appended on it.
Having this in mind, I'm thinking if there's a better way to do this, this is the code I've writed to do this.
function filterArray(arr, obj, key) {
for (let i = 0; i < arr.length; i++) {
if (arr[i][key] === obj[key]) {
const newArr = [...arr]
newArr.splice(i, 1)
return newArr
}
}
return [...arr, obj]
}
const fruits = [
{ id: 1, fruit: "Apple" },
{ id: 2, fruit: "Banana" },
{ id: 3, fruit: "Pineapple" }
]
const removedBanana = filterArray(fruits, {
id: 3,
fruit: "Banana"
}, "fruit")
const addedStrawberry = filterArray(fruits, {
id: 4,
fruit: "Strawberry"
}, "fruit")
console.log(removedBanana) // [ { id: 1, fruit: 'Apple' }, { id: 3, fruit: 'Pineapple' } ]
console.log(addedStrawberry)
// [
// { id: 1, fruit: 'Apple' },
// { id: 2, fruit: 'Banana' },
// { id: 3, fruit: 'Pineapple' },
// { id: 4, fruit: 'Strawberry' }
// ]
There's a better way to do this on ES6?
EDIT
If possible, I want to iterate the array only one time, making an O(n) algorithm
- do you want to mutate the array? – Nina Scholz Commented Jan 10, 2020 at 13:05
- @NinaScholz yes – Ricardo Mendes Commented Jan 10, 2020 at 13:05
- your code shows a new array ... – Nina Scholz Commented Jan 10, 2020 at 13:08
- Ops, sorry @NinaScholz, I don't want to mutate, I want to create a new one – Ricardo Mendes Commented Jan 10, 2020 at 13:41
4 Answers
Reset to default 8This approach mutates the array by looking for the index and splice if found or push the object to the array. The result has the same object reference than the handed over array.
function filterArray(array, object, key) {
var index = array.findIndex(o => o[key] === object[key]);
if (index === -1) array.push(object);
else array.splice(index, 1);
return array;
}
const
fruits = [{ id: 1, fruit: "Apple" }, { id: 2, fruit: "Banana" }, { id: 3, fruit: "Pineapple" }];
console.log(filterArray(fruits, { id: 3, fruit: "Banana" }, "fruit"));
console.log(filterArray(fruits, { id: 4, fruit: "Strawberry" }, "fruit"));
.as-console-wrapper { max-height: 100% !important; top: 0; }
For a nonmutating approach, you could get a copy in the head of the function and perform the same as above.
function filterArray([...array], object, key) {
function filterArray(array, object, key) {
var index = array.findIndex(o => o[key] === object[key]);
if (index === -1) array.push(object);
else array.splice(index, 1);
return array;
}
const
fruits = [{ id: 1, fruit: "Apple" }, { id: 2, fruit: "Banana" }, { id: 3, fruit: "Pineapple" }];
console.log(filterArray(fruits, { id: 3, fruit: "Banana" }, "fruit"));
console.log(filterArray(fruits, { id: 4, fruit: "Strawberry" }, "fruit"));
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use Array.some()
to check if the object exists, and if it does filter it out. If not, add it.
function filterArray(arr, obj, key) {
return arr.some(o => obj[key] === o[key]) ? // if you can find the object
arr.filter(o => obj[key] !== o[key]) // remove it
:
[...arr, obj] // or add it if not
}
const fruits = [{"id":1,"fruit":"Apple"},{"id":2,"fruit":"Banana"},{"id":3,"fruit":"Pineapple"}]
const removedBanana = filterArray(fruits, { id: 3, fruit: "Banana" }, "fruit")
const addedStrawberry = filterArray(fruits, { id: 4, fruit: "Strawberry" }, "fruit")
console.log(removedBanana) // [ { id: 1, fruit: 'Apple' }, { id: 3, fruit: 'Pineapple' } ]
console.log(addedStrawberry)
// [
// { id: 1, fruit: 'Apple' },
// { id: 2, fruit: 'Banana' },
// { id: 3, fruit: 'Pineapple' },
// { id: 4, fruit: 'Strawberry' }
// ]
There is a simple solution for this question:
function addObjToArray (arr, obj, key) {
const resultArr = arr.filter(arrObj => arrObj[key] !== obj[key])
if (resultArr.length === arr.length) resultArr.push(obj)
return resultArr
}
The filter
method will return an array with just objects that are different of obj[key]
. If filtered array is equal to original array, it push the object to resultArr
, else, just will return the initial resultArr
.
This is solution from my work colleague (https://stackoverflow.com/users/12691758/guilherme-ca%c3%a7ador-monteiro).
What you think?
By your requirements, and the additional requirement -- in comments -- that the collection should mutate, you would have a better tool by using an ES6 Map
:
const fruits = new Map([
{ id: 1, fruit: "Apple" },
{ id: 2, fruit: "Banana" },
{ id: 3, fruit: "Pineapple" }
].map (o => [o.fruit, o]));
fruits.key = "fruit"; // register the key field once
fruits.toggleItem = function (obj) {
if (!this.delete(obj[this.key])) this.set(obj[this.key], obj);
}
fruits.toggleItem({id: 3, fruit: "Banana"});
console.log([...fruits.values()]);
fruits.toggleItem({id: 4, fruit: "Strawberry"});
console.log([...fruits.values()]);