Delete an item from a JavaScript set - javascript

How to delete an item from a set with condition
if(item.id === 2){
mySet.delete(item)
}
I can't use mySet.has(item) because only common thing in the objects is the id.

Unless you already have a reference to the object, you'll have to iterate through the Set's values to .find the matching object, then call .delete with it:
const set = new Set([
{ id: 1 },
{ id: 2 },
]);
const obj = [...set].find(obj => obj.id === 2);
set.delete(obj);
console.log([...set]);

You can create array of remaining items like
var resultArr = [];
yourobj.forEach((item,index)=>{
if(item.id === 2)
{
// nothing
}
else
{
resultArr.push(item);
}
})

You can use a for ... of statement to locate and delete matching items from a set according to your conditions. And in case you are concerned, it's ok to delete an item from a set while iterating.
let mySet = new Set([
{ id: 1 },
{ id: 2 },
{ id: 3 }
]);
for (const item of mySet) if (item.id == 2) { mySet.delete(item); /*optional*/ break; }
console.log([...mySet]);
If there are multiple matching items, you can omit the break in this example.

similar immutable way to do this in one line:
const result = mySet.filter(x => x.id === 2);

Related

Remove Nullish values from multidimensional array?

I have an array res with some nullish values, and I have a function remove that is supposed return an array with nulls and undefined removed, but I can't get it to work on my array. I've seen plenty of answers on this sort of thing, in fact my remove function originated from one of them, but I can't seem to get it to work.
res =
[
{
"1yKKftO0iOyvsacrW1mEr-FylurU8-fwaefewafw": [
"raggy#champ.co",
"grope#champ.co",
null,
"halp#champ.co"
]
},
{
"149Lmt-gweagewfrthjregjiojoinONEDOnonao": [
"raggy#champ.co"
]
},
{
"JG043AHF0GJA0EWJIFJO00WIJF-UffFWEAk8QRg4": [
"wlyman#champ.co",
"raggy#champ.co"
]
},
{
"1u-Frw5I4agI-FWKE0AFJ0WEJG0JEFDALKFEWA-ns": [
null,
"raggy#champ.co"
]
},
{
"FAWGETAIODIOFAIJDSOIFJWEOFijewaofifejowef": [
"raggy#champ.co"
]
},
{
"fwaejf0JF0EWJIJFFJMojfeoijfewJEJFI0i0fje": [
"raggy#champ.co"
]
},
{
"FJ09Ejf093ejfie0jfeiJFEJF0IWJFEIJFOEJWow": [
"raggy#champ.co"
]
}
]
var remove = function (array) {
var result = [];
array.forEach(function (item) {
if (Array.isArray(item) && item.length!=0) {
// Item is a nested array, go one level deeper recursively
result.push(remove(item));
}
else if (typeof item !== null) {
result.push(item);
}
});
return result;
};
console.log(remove(res));
Here is a solution without recursion that will work for the nesting level given in example. Also will work if a single array element has multiple key value pairs.
let res =[{"1yKKftO0iOyvsacrW1mEr-FylurU8-fwaefewafw": ["raggy#champ.co","grope#champ.co",null,"halp#champ.co"]},{"149Lmt-gweagewfrthjregjiojoinONEDOnonao": ["raggy#champ.co"]},{"JG043AHF0GJA0EWJIFJO00WIJF-UffFWEAk8QRg4": ["wlyman#champ.co","raggy#champ.co"]},{"1u-Frw5I4agI-FWKE0AFJ0WEJG0JEFDALKFEWA-ns": [undefined,"raggy#champ.co"]},{"FAWGETAIODIOFAIJDSOIFJWEOFijewaofifejowef": ["raggy#champ.co"]},{"fwaejf0JF0EWJIJFFJMojfeoijfewJEJFI0i0fje": ["raggy#champ.co"]},{"FJ09Ejf093ejfie0jfeiJFEJF0IWJFEIJFOEJWow": ["raggy#champ.co",null]}]
var remove = function (array) {
return array.map(function (item) {
let x = Object.entries(item).map((y) => {
return [y[0],y[1].filter((z)=> z!==undefined && z!==null)]
})
return Object.fromEntries(x)
});
};
console.log(remove(res));
If you want to remove nulls as well as undefineds, you probably want to replace else if (typeof item !== null) with else if (typeof item != null)
What's happening
The elements of res are Objects.
Notice that in the nested function call of remove
result.push(remove(item));
the item being passed are elements of res thus not an array. So when remove(item) is called the check Array.isArray(item) fails and nothing is sorted out.
To get the inner array make add this line.
var values = Object.values(item)
Now handle the cases of item being null, Object and Array.
Solution
Here's my Attempt at the solution. (I hope you don't mind ES6)
This does work on this particular (not sure about other cases)
const remove = (item) => {
if (item) {
console.log('not null', item)
if (Array.isArray(item)) {
const result = []
for (let elem of item) {
const cleanedElem = remove(elem)
// Maybe use Nullish coalescing operator ?
if (cleanedElem !== null && cleanedElem !== undefined)
result.push(cleanedElem)
}
return result
} else if (typeof item === 'string' || typeof item === 'number') {
return item
} else if (item) {
const result = {}
for (let pair of Object.entries(item)) {
const [key, value] = pair
const cleanedValue = remove(value)
// Maybe use Nullish coalescing operator ?
if (cleanedValue !== null && cleanedValue !== undefined)
result[key] = remove(cleanedValue)
}
return result
}
}
}
cleansed = remove(res)
console.log(cleansed);

Find an index of array item from another json array item

I am looking to find out an index and group the item belong to in a parent json group, how can I do it?
I am open to reformat the json as well if need be,
I tried JSON.stringify() but it returns the wrong index as well.
let Content = {
group1: [
[{content:"hello"},{content:"world"}],
[{content:"hello1"},{content:"world"}],
[{content:"hello2"},{content:"world"}],
[{content:"hello3"},{content:"world"}],
[{content:"hello4"},{content:"world"}],
[{content:"hello5"},{content:"world"}],
],
group2: [
[{content:"hello10"},{content:"world"}],
[{content:"hello11"},{content:"world"}],
[{content:"hello12"},{content:"world"}],
[{content:"hello13"},{content:"world"}],
[{content:"hello14"},{content:"world"}],
[{content:"hello15"},{content:"world"}],
],
};
// let currentItem = {type:'group2',index:5};
// let currentItemContent = Content[currentItem.type][currentItem.index];
let obj = [{content:"hello15"},{content:"world"}];
let newIndex = Content["group1"].indexOf(obj);
let type = "group1";
if(newIndex < 0)
{
type="group2"
console.log(Content["group2"]);
newIndex = Content["group2"].indexOf(obj);
}
console.log({"type":type,"index":newIndex});
expected: {type:'group2',index:5}
Loop through the Content object using for...in. Check if the given array is in each group by using findIndex. Since both the objects in the array seem to be in order, you can simply compare the string returned by JSON.stringify
let Content={group1:[[{content:"hello"},{content:"world"}],[{content:"hello1"},{content:"world"}],[{content:"hello2"},{content:"world"}],[{content:"hello3"},{content:"world"}],[{content:"hello4"},{content:"world"}],[{content:"hello5"},{content:"world"}]],group2:[[{content:"hello10"},{content:"world"}],[{content:"hello11"},{content:"world"}],[{content:"hello12"},{content:"world"}],[{content:"hello13"},{content:"world"}],[{content:"hello14"},{content:"world"}],[{content:"hello15"},{content:"world"}]]}
function find(input, search) {
for (const type in input) {
const group = input[type];
const index = group.findIndex(a => JSON.stringify(a) === JSON.stringify(search));
if (index != -1)
return { type, index }
}
return null
}
console.log(find(Content, [{content:"hello15"},{content:"world"}]))
console.log(find(Content, [{content:"hello"},{content:"world"}]))
You could also use Array.find in combination with Object.keys and Array.some. The array comparison you can do via JSON.stringify however remember that if your keys are in different order that would not work:
[{content:"world"},{content:"hello"}] vs [{content:"hello"},{content:"world"}]
would not match as you would expect since you are matching on strings and they are now different.
let Content = { group1: [ [{content:"hello"},{content:"world"}], [{content:"hello1"},{content:"world"}], [{content:"hello2"},{content:"world"}], [{content:"hello3"},{content:"world"}], [{content:"hello4"},{content:"world"}], [{content:"hello5"},{content:"world"}], ], group2: [ [{content:"hello10"},{content:"world"}], [{content:"hello11"},{content:"world"}], [{content:"hello12"},{content:"world"}], [{content:"hello13"},{content:"world"}], [{content:"hello14"},{content:"world"}], [{content:"hello15"},{content:"world"}], ], };
let findArray = (data, obj) => {
let index, group = Object.keys(data).find((k,i) => {
index = i
return data[k].some(x => JSON.stringify(x) === JSON.stringify(obj))
})
return { index, group }
}
console.log(findArray(Content, [{content:"hello"},{content:"world"}]))
console.log(findArray(Content, [{content:"hello10"},{content:"world"}]))

How to remove an element from a key value array?

I want to remove a specific element from an array, I am getting the key of the element from the input.
I want to be able to remove the element only by knowing the key.
This is the array:
state ={
splitAmount : [{
"SplitAmount0": this.props.data.amount1
}, {
"SplitAmount1": this.props.data.amount2
}, {
"SplitAmount2": this.props.data.amount3
}]
}
Remove function:
removeSplitAmount(e) {
console.log("remove",e.target.name)
let array = [...this.state.splitAmount];
let index = this.state.splitAmount.IndexOf(p => p == e.target.name )
if (index !== -1) {
array.splice(index, 1);
this.setState({splitAmount: array});
}
}
You can use the .filter method on the array combined with the Object.keys to clean the function up a lot:
removeSplitAmount(e) {
const newSplitAmount = this.state.splitAmount
.filter(p => !Object.keys(p).includes(e.target.name));
this.setState({ splitAmount: newSplitAmount });
}
You can use hasOwnProperty to filter objects you need.
removeSplitAmount(e) {
const newSplitAmount = this.state.splitAmount
.filter(x => !x.hasOwnProperty(e.target.name));
this.setState({ splitAmount: newSplitAmount });
}
As Dmitry said you can't do a indexOf on an array of objects... i felt bad i didn't realize that.
Would be useful on this case:
var beasts = ['ant', 'bison', 'camel', 'duck', 'bison'];
beasts.indexOf('bison')
On your case you are better to go with the .filter method as said in above answers because you are searching for and object with a specific property

Filterring an Array of Objects

Im trying to do a check if one of the objects in the Array has the id of 2 if so remove that object. list.filter(e => e.id === 2) returns[ { name: 'bread', id: 2 } ] which is the part i want to remove but if i check if it is in the array by doing if(list.indexOf(list.filter(e => e.id === 2)) != -1) it returns -1 saying its not in the list. Any help would be apreciated!
var list = new Array();
list.push({name: 'apple', id: 1})
list.push({name: 'bread', id: 2})
console.log(list.filter(e => e.id === 2));
console.log(list);
if(list.indexOf(list.filter(e => e.id === 2)) != -1) {
list.splice(list.indexOf(list.filter(e => e.name === 2)));
console.log(list);
} else {
console.log('The id of 2 has not been found');
}
Then just use !== instead ===.
But you can use find method.
var elem = list.find(e => e.id === 2);
if(elem)
list = list.filter(e => e.id !== 2);
else
console.log('The id of 2 has not been found');
You are using filter, like it filters out elements, while it actually keeps elements that fit the condition. Change your condition to e.id !== 2 and it keeps all elements with ids not equal to 2:
var list = new Array();
list.push({name: 'apple', id: 1})
list.push({name: 'bread', id: 2})
list.push({name: 'milk', id: 3})
list.push({name: 'butter', id: 4})
console.log(list.filter(e => e.id !== 2));
.as-console-wrapper { max-height: 100% !important; top: 0; }
You need to invert the logic of the filter predicate function.
list.filter(e => e.id !== 2);
filter returns only the items that match the predicate - in your case it will return a list of only one element which has the ID of 2.
Testing with indexOf you're searching for an array with the element that you've found.
filter returns an array with the results. You should use find instead which returns a single element:
var list = new Array();
list.push({name: 'apple', id: 1})
list.push({name: 'bread', id: 2})
var index = list.indexOf(list.find(e => e.id === 2));
var result = index !== -1;
console.log('index', index);
console.log('result', result);
When you use list.filter(e => e.name === 2). It will return an array include the object , not the object itself. So it will return -1. You can use the spread syntax to extract the object out of the array contain it:
list.indexOf(...list.filter(e => e.id === 2))
indexOf won't work as you will be searching for an object and object comparison in JavaScript is tricky (a custom evaluater is needed to check sameness). The good news is you may not need it.
As noted in comments and elsewhere, filter was behaving opposite to what you desired. Changing the comparison operator from === to !== is one way to solve that issue.
In the code below, I've included some other goodies you may find value, such as:
the Array.of()
shorthand property names (e.g., { foo } === {'foo': foo})
series execution using the comma operator (i.e. ,) especially to avoid curly-braces
... as a rest operator for function arguments
and others
let search_id = 2; // id to filter out
let list = Array.of(
{name: 'apple', id: 1},
{name: 'bread', id: 2},
{name: 'orange', id: 3},
{name: 'bagel', id: 4}
)
log({list});
let filtered = list.filter(e => e.id !== search_id)
log({filtered});
if (filtered.length)
log(`Found ${filtered.length} matches!`);
else
log(`The id of ${search_id} has not been found`);
// Simple logger so label is on its own line
function log(){
let [param1,...args]=arguments;
switch (typeof param1){
case 'string':
if (args.length)
console.log(`${param1}:`), // comma intentional
console.log(args.pop())
else
console.log(param1);
break;
case 'object':
for (let key in param1)
console.log(`${key}:`), // comma intentional
console.log(param1[key])
break;
default:
console.log('Error in passed arguments. Type not recognized.')
}
}

match an object in an array of objects and remove

After 2 days of fighting this problem I'm hoping someone can help me out.
I have two arrays of objects, like this:
let oldRecords = [
{name: 'john'},
{name: 'ringo'}
];
let newRecords = [
{name: 'paul'},
{name: 'john'},
{name: 'stuart'}
];
I am trying to end up with a function that returns named variables containing a list of data thats been added (exist in newRecords but not in oldRecords) and a list of data that has been removed (exists in oldRecords but not in newRecords).
for example
const analyse = (older, newer) => {
let added, removed;
// ... magic
return {added, removed}
}
const {added, removed} = analyse(oldRecords, newRecords);
I won't post all the code I've tried inside this function as I have tried to map, reduce and loop through both arrays creating temporary arrays for the last 48 hours and I could now fill a book with code I've written and deleted. I have also used underscore.js methods like reject/find/findWhere which all got me close but no cigar.
the main issue I am having is because the arrays contain objects, its super easy if they contain numbers, i.e.
var oldRecords = [1, 3];
var newRecords = [1, 2, 4]
function analyse (old, newer) {
let added = [];
let removed = [];
old.reduce((o) => {
added = added.concat(_.reject(newer, (num) => num === o ));
});
newer.reduce((n) => {
removed = _.reject(old, (num) => num === n );
});
return {added, removed}
}
const {added, removed} = analyse(oldRecords, newRecords);
How can I achieve the above but with objects not arrays?
n.b. I tried modifying the above and using JSON.stringify but it didn't really work.
EDIT: important point I forgot to add, the object structure adn it's keys are dynamic, they come from a database, so any individual checking of a key must also be dynamic, i.e. not a hard coded value
You could use reject and some to check for inclusion in the appropriate sets. The isEqual function is used to check for equality to handle dynamic keys:
const analyse = (older, newer) => {
let added = _.reject(newer, n => _.some(older, o =>_.isEqual(n, o)));
let removed = _.reject(older, o => _.some(newer, n => _.isEqual(n, o)));
return {added, removed}
}
You could try this:
const analyse = (older, newer) => {
let removed = older.filter(newItem => {
return newer.filter(oldItem => {
return _.isEqual(newItem, oldItem);
}).length === 0
});
let added = newer.filter(oldItem => {
return older.filter(newItem => {
return _.isEqual(newItem, oldItem);
}).length === 0
});
return {added, removed};
}
You can first create function to check if two object are equal, end then use filter() and some() to return result.
let oldRecords = [
{name: 'john'},
{name: 'ringo'}
];
let newRecords = [
{name: 'paul'},
{name: 'john'},
{name: 'stuart'}
];
function isEqual(o1, o2) {
return Object.keys(o1).length == Object.keys(o2).length &&
Object.keys(o1).every(function(key) {
return o2.hasOwnProperty(key) && o1[key] == o2[key]
})
}
var result = {}
result.removed = oldRecords.filter(e => !newRecords.some(a => isEqual(e, a)))
result.added = newRecords.filter(e => !oldRecords.some(a => isEqual(e, a)))
console.log(result)

Categories

Resources