Delete object from array in JavaScript - javascript

I have an array and I want to delete an object in it.
I only have the complete object and I want to delete from the array inside it.
Object = {Comments: [{text: 'hello', x:200, y:100},
{text: 'hi', x:565, y:454},
{text: 'Hola', x:454, y:235}
]
};
I want to delete this object :
toDelete = {text: 'hi', x:565, y:454}
How can I do this?

You can use
Object.Comments.splice(1, 1);
But you should also give your variable a different name and use let or var.

You can use filter to remove an item from an array:
const myArray = [
{ text: 'one', digit: 1 },
{ text: 'two', digit: 2 },
{ text: 'three', digit: 3 }
];
const filteredArray = myArray.filter(item => {
return item.text !== 'two' && item.digit !== 2
});
console.log(filteredArray); // [ { text: 'one', digit: 1 }, { text: 'three', digit: 3 } ]

You should use a unique id for comments array.
var Object = {
Comments: [{
id: 1,
text: 'hello',
x: 200,
y: 100
},
{
id: 2,
text: 'hi',
x: 565,
y: 454
},
{
id: 3,
text: 'Hola',
x: 454,
y: 235
}
]
};
const {
Comments
} = Object;
function deleteComment = (itemArray, id) => {
return itemArray.filter(itm => {
return itm.id !== id
})
}
const filterdArray = deleteComment(Comments, passYourTargetId);
// in this filterdArray you get without that item you want to remove and it work with immutable way

Related

Compare two objects in an array, delete the duplicate data, and combine the different data?

I am getting a list of objects in an array, some of which are duplicates. However, the condition that produces the duplicates is different.
So picture an array:
var array = [{id: 1, name: 'test', condition: 'left'},
{id: 2, name: 'example', condition: 'left'},
{id: 1, name: 'test', condition: 'right'},
{id: 3, name: 'foobar', condition: 'right'}]
What I am looking for:
var solution = [{id: 1, name: 'test', condition: ['left', 'right']},
{id: 2, name: 'example', condition: 'left'},
{id: 3, name: 'foobar', condition: 'right'}]
I am able to delete duplicates no problem using this method:
var available = result.reduce((unique, o) => {
if (!unique.some((obj) => obj.id === o.id && obj.name === o.name)) {
unique.push(o);
}
return unique;
}, []);
But would Like to combine the condition data
You could collect all with an object with combined keys.
const
array = [{ id: 1, name: 'test', condition: 'left' }, { id: 2, name: 'example', condition: 'left' }, { id: 1, name: 'test', condition: 'right' }, { id: 3, name: 'foobar', condition: 'right' }],
keys = ['id', 'name'],
result = Object.values(array.reduce((r, o) => {
const key = keys.map(k => o[k]).join('|');
if (r[key]) r[key].condition = [].concat(r[key].condition, o.condition);
else r[key] = { ...o };
return r;
}, {}));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Here's a concise solution with 4 steps that only checks for unique IDs:
find the unique IDs
for each unique ID, find the values of that ID
for each group of values with the same ID, find the unique conditions
for each group of values with the same ID, create 1 output value with the unique ID, name, and conditions
let array = [{id: 1, name: 'test', condition: 'left'},
{id: 2, name: 'example', condition: 'left'},
{id: 1, name: 'test', condition: 'right'},
{id: 3, name: 'foobar', condition: 'right'}];
let groupedById = [...new Set(array.map(v => v.id))]
.map(id => {
let valuesWithId = array.filter(v => v.id === id);
let condition = [...new Set(valuesWithId.map(v => v.condition))];
return { ...valuesWithId[0], condition};
});
console.log(groupedById);
If you really have data that has values of the same ID but different names, this can be expanded to:
Iterate the input array, and for each value:
If it has an unseen ID & name combination, add it to the output (after transforming condition to an array).
If it has a seen ID & name combination, add it's condition to its existing counterpart (if it's not present already).
let array = [{id: 1, name: 'test', condition: 'left'},
{id: 2, name: 'example', condition: 'left'},
{id: 1, name: 'test', condition: 'right'},
{id: 3, name: 'foobar', condition: 'right'}];
let groupedByIdAndName = [];
array.forEach(value => {
let duplicate = groupedByIdAndName.find(v => v.id === value.id && v.name === value.name);
if (!duplicate)
groupedByIdAndName.push({...value, condition: [value.condition]});
else if (duplicate.condition.every(c => c !== value.condition))
duplicate.condition.push(value.condition);
});
console.log(groupedByIdAndName);
You can accomplish this in two steps.
Group the data by the id
Merge values for each group by combining the values of their properties
const array = [
{ id: 1 , name: 'test' , condition: 'left' },
{ id: 2 , name: 'example' , condition: 'left' },
{ id: 1 , name: 'test' , condition: 'right' },
{ id: 3 , name: 'foobar' , condition: 'right' }
];
const groupBy = (key, objs) => objs.reduce((acc, obj) =>
({ ...acc, [obj[key]]: [...(acc[obj[key]] || []), obj] }), {});
const combine = (newVal, oldVal) =>
oldVal != null
? Array.isArray(oldVal)
? !oldVal.includes(newVal)
? [ ...oldVal, newVal ]
: oldVal
: oldVal !== newVal
? [ oldVal, newVal ]
: oldVal
: newVal;
const merge = (objs) => objs.reduce((acc, obj) =>
Object.keys(obj).reduce((acc1, key) =>
({ ...acc1, [key]: combine(obj[key], acc1[key]) }), acc), {});
const groupByAndMerge = (key, items) =>
Object.values(groupBy(key, items)).map(merge);
console.log(groupByAndMerge('id', array));
.as-console-wrapper { top: 0; max-height: 100% !important; }
Code golf
I reduced the function to a single-line statement with a size of 259 bytes.
// Size: 259 bytes
f=(k,a)=>Object.values(a.reduce((r,i)=>({...r,[i[k]]:[...(r[i[k]]||[]),i]}),{})).map(g=>g.reduce((s,o)=>Object.keys(o).reduce((t,m)=>({...t,[m]:t[m]!=null?Array.isArray(t[m])?!t[m].includes(o[m])?[...t[m],o[m]]:t[m]:t[m]!==o[m]?[t[m],o[m]]:t[m]:o[m]}),s),{}))
console.log(f('id',[{id:1,name:'test',condition:'left'},{id:2,name:'example',condition:'left'},{id:1,name:'test',condition:'right'},{id:3,name:'foobar',condition:'right'}]));
.as-console-wrapper { top: 0; max-height: 100% !important; }

Check key in deep nested object in array

I have array of nested object. I have to check the property of key object and return its value. I have done it using the for loop and checking with children property exist or not. But I think it is not optimal way to do it. what will be most optimal way to do it. Here is the code array of object data. I have to get text for the id 121.
var abc = [
{
id: 1,
text: 'One',
children: [
{id: 11, text: 'One One'},
{id: 12, text: 'One two',
children: [ {id: 121, text: 'one two one'} ]}
]
},
{
id: 2,
text: 'two'
}
];
My approach is very specific to this problem. Here it is
for(var val of abc){
if(val.id == 121){
console.log('in first loop',val.text);
break;
}
if(Array.isArray(val.children)){
for(var childVal of val.children) {
if(childVal.id == 121){
console.log('in first child', childVal.text);
break;
}
if(Array.isArray(childVal.children)){
for(var nextChild of childVal.children){
if(nextChild.id == 121){
console.log('in next child', nextChild.text);
break;
}
}
}
}
}
}
You could create recursive function using for...in loop that returns the matched object and then you can get its text property.
var abc = [{"id":1,"text":"One","children":[{"id":11,"text":"One One"},{"id":12,"text":"One two","children":[{"id":121,"text":"one two one"}]}]},{"id":2,"text":"two"}]
function getProp(data, key, value) {
let result = null;
for (let i in data) {
if (typeof data[i] == 'object' && !result) {
result = getProp(data[i], key, value)
}
if (i == key && data[i] == value) {
result = data
}
}
return result;
}
const result = getProp(abc, 'id', 121)
console.log(result)
You could take an approach with a short circuit and return a result from a wanted property.
const
getValue = (object, key, id) => {
const search = o => {
if (!o || typeof o !== 'object') return;
if (o.id === id) return { value: o[key] };
var value;
Object.values(o).some(p => value = search(p));
return value;
};
return search(object)?.value;
};
var array = [{ id: 1, text: 'One', children: [{ id: 11, text: 'One One' }, { id: 12, text: 'One two', children: [{ id: 121, text: 'one two one' }] }] }, { id: 2, text: 'two' }];
console.log(getValue(array, 'text', 121));
console.log(getValue(array, 'text', 3000));
Given your Nodes have nested Nodes in a children property, using a recursion and Array.prototype.find() to find a Node by ID:
const getNode = (a, id, c = 'children', r) => {
const rec = a => a.find(o => o.id==id && (r=o) || c in o && rec(o[c]));
return rec(a) && r;
};
const abc = [{id: 1, text: 'One', children: [{id: 11, text: 'One one'}, {id: 12, text: 'One two', children: [{id: 121, text: 'One two one'}]}]}, {id: 2, text: 'Two' }];
console.log( getNode(abc, 121)?.text ); // One two one

Creating a reduced set and nested array within an array of objects

I'm trying to wrap my head around transforming an array of "flat" objects, into a condensed but nested version:
const startingArray = [
{ name: 'one', id: 100, thing: 1 },
{ name: 'one', id: 100, thing: 2 },
{ name: 'one', id: 100, thing: 4 },
{ name: 'two', id: 200, thing: 5 }
];
/*
desiredResult = [
{name: 'one', id:100, things: [
{thing: 1}, {thing: 2}, {thing:4}
]},
{name: 'two', id:200, things: [
{thing: 5}
]}
]
*/
// THIS DOES NOT WORK
const result = startingArray.reduce((acc, curr) => {
if (acc.name) {
acc.things.push(curr.thing)
}
return { name: curr.name, id: curr.id, things: [{thing: curr.thing}] };
}, {});
What am I not understanding?!
In your reduce callback, acc is not "each element of the array" (that's what curr is) or "the matching element in the results" (you have to determine this yourself), it's the accumulated object being transformed with each call to the function.
That is to say, when you return { name: curr.name, id: curr.id, things: [{thing: curr.thing}] };, it sets acc to that object for the next iteration, discarding whatever data was contained in it before - acc.name will only ever hold the last name iterated over and the results will never accumulate into anything meaningful.
What you want to do is accumulate the results in an array (because it's your desired output), making sure to return that array each iteration:
const startingArray = [
{ name: 'one', id: 100, thing: 1 },
{ name: 'one', id: 100, thing: 2 },
{ name: 'one', id: 100, thing: 4 },
{ name: 'two', id: 200, thing: 5 }
];
const result = startingArray.reduce((acc, curr) => {
let existing = acc.find(o => o.id == curr.id);
if(!existing) acc.push(existing = { name: curr.name, id: curr.id, things: [] });
existing.things.push({thing: curr.thing});
return acc;
}, []);
console.log(result);
Because of your desired result format this involves quite a few acc.find() calls, which is expensive - you can get around this in a concise way with this trick, using the first element of the accumulator array as a mapping of ids to references (also featuring ES6 destructuring):
const startingArray = [
{ name: 'one', id: 100, thing: 1 },
{ name: 'one', id: 100, thing: 2 },
{ name: 'one', id: 100, thing: 4 },
{ name: 'two', id: 200, thing: 5 }
];
const result = startingArray.reduce((acc, {name, id, thing}) => {
if(!acc[0][id])
acc.push(acc[0][id] = { name, id, things: [] });
acc[0][id].things.push({thing});
return acc;
}, [{}]).slice(1); //slice off the mapping as it's no longer needed
console.log(result);
Ok, providing alternative way. Key point is that you accumulate an Object and later take only the values, so get an Array:
const startingArray = [
{ name: 'one', id: 100, thing: 1 },
{ name: 'one', id: 100, thing: 2 },
{ name: 'one', id: 100, thing: 4 },
{ name: 'two', id: 200, thing: 5 }
];
const res = startingArray.reduce((acc, curr) => {
if (acc[curr.name]) {
acc[curr.name].things.push({thing: curr.thing})
} else {
acc[curr.name] = {
name: curr.name,
id: curr.id,
things: [{thing: curr.thing}]
}
}
return acc
}, {})
console.log(Object.values(res))

How to check an object for a value

Hey I created my first app in react native and i run into some trouble, i simple would like to know how i can check an object for an specific value from a local storage. This is what i have so far, i know its not that much.
handleClick = (item)=>{
store.get('myobject').then((res) =>
console.log(res)
)
this is my res object:
[
{ id: '456', p: 'hey' },
{ id: '464', p: 'ho' },
{ id: '467', p: 'lets' },
{ id: '263', p: 'go' }
]
and as example i would like to know, if id 467 is in the object.
You could make use of the some method of Array:
var res = [
{ id: '456', p: 'hey' },
{ id: '464', p: 'ho' },
{ id: '467', p: 'lets' },
{ id: '263', p: 'go' }
];
var found = res.some(item => item.id === '467');
console.log(found);
Essentially, as it is stated here
The some() method tests whether at-least one element in the array
passes the test implemented by the provided function.
You could do a forEach loop and check for your desired value:
var res = [
{ id: '456', p: 'hey' },
{ id: '464', p: 'ho' },
{ id: '467', p: 'lets' },
{ id: '263', p: 'go' }
]
function containsCheck(array) {
var found = false;
array.forEach(function(element) {
if (element.id === '467') {
found = true;
}
});
return found;
};
console.log(containsCheck(res));
As an alternative you can check Lodash This lib is a nice thing to have in a project when working with collections or objects.

Zipping two collections with possible null values in Javascript (lodash available)

I have two arrays of objects. Each collection object contains similar properties. I'm trying to zip together the two collections based on a specific property. It's possible, however, that a particular object in either array may not necessarily have a object with a matching property value in the other array. In these cases I'd like to have null values. Here's an example of what I'd like to do:
var arr1 = [
{ id: '1', text: 'arr1 - one' },
{ id: '2', text: 'arr1 - two' },
{ id: '3', text: 'arr1 - three' }
];
var arr2 = [
{ id: '1', text: 'arr2 - one' },
{ id: '2', text: 'arr2 - two' },
{ id: '4', text: 'arr2 - four' }
];
result:
{
'1': [
{ id: '1', text: 'arr1 - one' },
{ id: '1', text: 'arr2 - one' }
]
'2': [
{ id: '2', text: 'arr1 - two' },
{ id: '2', text: 'arr2 - two' }
],
'3': [
{ id: '3', text: 'arr1 - three' },
null
],
'4': [
null,
{ id: '4', text: 'arr2 - four' }
]
I do already have a lodash 4 dependency in the project, so answers using that library are welcome.
_.chain(arr1)
.concat(arr2)
.map('id')
.uniq() //get all possible ids without dublicates
.reduce(function (result, id) {
result[id] = _.map([arr1, arr2], function (arr) { //find object in each array by id
return _.find(arr, {id: id}) || null; //if not found set null
});
return result;
}, {})
.value();
function zip(a, b, propName) {
const result = new Map();
a.forEach(i=> result.set(i[propName], [i, null]));
b.forEach(i=> {
let item = result.get(i[propName]);
item ? (item[1] = i) : (result.set(i[propName], [null, i]));
});
return result;
}
var arr1 = [
{ id: '1', text: 'arr1 - one' },
{ id: '2', text: 'arr1 - two' },
{ id: '3', text: 'arr1 - three' }
];
var arr2 = [
{ id: '1', text: 'arr2 - one' },
{ id: '2', text: 'arr2 - two' },
{ id: '4', text: 'arr2 - four' }
];
console.log(JSON.stringify([...zip(arr1, arr2, 'id')], null, ' '));
According to the requirements listed, below should work (using Ramda, I believe the functions used should have according one in lodash/fp)
var arr1 = [
{ id: '3', text: 'arr1 - one' },
{ id: '2', text: 'arr1 - two' },
{ id: '1', text: 'arr1 - three' }
];
var arr2 = [
{ id: '4', text: 'arr2 - one' },
{ id: '2', text: 'arr2 - two' },
{ id: '1', text: 'arr2 - four' }
];
var idList = R.pipe(
R.concat,
R.map(R.prop('id')),
R.uniq,
R.sortBy(R.identity)
)(arr1, arr2);
var findById = (id) => R.find(R.propEq('id', id));
return R.map(
(id) => [
findById(id)(arr1),
findById(id)(arr2)
]
)(idList);
Here's the link. It's returning undefined instead of null, but you can map over it to change it if it matters.
However, depending on what the result would be used, if null value is not required at all, there is simpler version with groupWith
return R.pipe(
R.concat,
R.sortBy(R.prop('id')),
R.groupWith(R.eqProps('id'))
)(arr1, arr2);
link.
The thing that makes this a bit difficult is the need for null values in each grouping, which match the order in which they were grouped. For example, if you did not need the nulls, this problem would be as simple as:
_.groupBy(arr1.concat(arr2), 'id')
However, to group and maintain nulls, you need to add a bit of redundancy that groupBy does not come pre-baked with. You can write your own group function as such:
function group(...arrs) { // extensible to any number of arrays
// construct an object with empty arrays for all available ids
let rslt = _.chain(arrs)
.flatten()
.map(el => el.id)
.uniq()
.reduce((memo, el) => {
memo[el] = []
return memo
}, {})
.value()
// as we iterate, first set resulting object's bucket value to null
// Replace this value if it exists while iterating
_.each(arrs, (arr, i) => {
_.each(rslt, v => {
v.push(null)
})
_.each(arr, el => {
rslt[el.id][i] = el
})
})
return rslt
}
var arr1 = [{
id: '3',
text: 'arr1 - one'
}, {
id: '2',
text: 'arr1 - two'
}, {
id: '1',
text: 'arr1 - three'
}];
var arr2 = [{
id: '4',
text: 'arr2 - one'
}, {
id: '2',
text: 'arr2 - two'
}, {
id: '1',
text: 'arr2 - four'
}];
console.log(group(arr1, arr2))
<script src="https://cdn.jsdelivr.net/lodash/4.17.2/lodash.min.js"></script>
^ Run the snippet to see a log of the result.
You can do this with _.groupBy() and _.mapValues():
const zipByKey = (arr1, arr2, zipKey) => {
// group arr2 by the zipKey
const group2 = _.groupBy(arr2, zipKey);
return _(arr1)
// group arr1 by the zipKey
.groupBy(zipKey)
// merge group1 with group2, if object is not in group1 substitute with null
.mergeWith(group2, (objValue, srcValue) => (objValue || [null]).concat(srcValue))
// map the groups, if object is not in group2 substitute with null
.mapValues((group, zipKey) => group2[zipKey] ? group : group.concat(null))
.value();
}
const arr1 = [{"id":"1","text":"arr1 - one"},{"id":"2","text":"arr1 - two"},{"id":"3","text":"arr1 - three"}], arr2 = [{"id":"1","text":"arr2 - one"},{"id":"2","text":"arr2 - two"},{"id":"4","text":"arr2 - four"}];
const result = zipByKey(arr1, arr2, 'id');
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.2/lodash.min.js"></script>

Categories

Resources