I have a nested object of this structure.
mainObject: {
1: {
id: 1,
name:'alpha'
},
2: {
id: 2,
name:'beta'
},
3: {
id: 3,
name:'gamma'
}
}
i want to delete on object from this ,say 1 but that in an immutable way . I tried the following code.
const list =Object.values(mainObject)
const newList=list.filter((item)=>{item.id!=1})
newList.forEach((item)=>{
mainObject[item.id]={
id: item.id,
name:item.name
}
})
this is not working .What am i doing wrong. Thanks in advance.
You could use destruct assignment for deletion
const { 1: _, ...newObject } = mainObject
const mainObject = {
1: {
id: 1,
name: "alpha",
},
2: {
id: 2,
name: "beta",
},
3: {
id: 3,
name: "gamma",
},
}
const { 1: _, ...newObject } = mainObject
console.log(mainObject)
console.log(newObject)
Or clone mainObject in to an different object then apply deletion
const newObject = { ...mainObject }
delete newObject[1]
const mainObject = {
1: {
id: 1,
name: "alpha",
},
2: {
id: 2,
name: "beta",
},
3: {
id: 3,
name: "gamma",
},
}
const newObject = { ...mainObject }
delete newObject[1]
console.log(mainObject)
console.log(newObject)
Or transform object into array of key-value pairs, reject your delete pair and then transform it back to object
const newObject = Object.fromEntries(
Object.entries(mainObject).filter(([key]) => key !== "1")
)
const mainObject = {
1: {
id: 1,
name: "alpha",
},
2: {
id: 2,
name: "beta",
},
3: {
id: 3,
name: "gamma",
},
}
const newObject = Object.fromEntries(
Object.entries(mainObject).filter(([key]) => key !== "1")
)
console.log(mainObject)
console.log(newObject)
Reference
Destructuring assignment
Spread operator (...)
Object.prototype.entries()
Object.prototype.fromEntries()
You can use delete operator and spread syntax to achieve what you want.
For the object you have mentioned, let me walk you through it.
const mainObject = {
1: {
id: 1,
name: 'alpha',
},
2: {
id: 2,
name: 'beta',
},
3: {
id: 3,
name: 'gamma',
},
};
const newObj = { ...mainObject};
delete newObj["1"];
Read More on Spread syntax on MDN
Read More on delete operator on MDN
Hope it helps🙂
const mainObject = {
1: {
id: 1,
name: 'alpha',
},
2: {
id: 2,
name: 'beta',
},
3: {
id: 3,
name: 'gamma',
},
};
const newObj = { ...mainObject};
delete newObj["1"];
document.write(`<p>mainObject:</p> <pre> ${JSON.stringify(mainObject)} </pre>`)
document.write(`<p>newObj:</p> <pre> ${JSON.stringify(newObj)} </pre>`)
Related
I have the following array and object I would like to 'match'
const items = [
{ key: 1, name: 'A', owner: 'Alex', },
{ key: 2, name: 'B', owner: 'Barb', },
{ key: 3, name: 'C', owner: 'John', },
{ key: 4, name: 'D', owner: 'Barb', },
{ key: 5, name: 'E', owner: 'Alex', },
];
const owners = {
'Alex': { 1: [], 5: [] },
'John': { 3: [], },
'Barb': { 2: [], 4: [] },
}
I would like to have the following end result:
const ownersWithName = {
'Alex': [{ key: 1, name: 'A', }, { key: 5, name: 'E' }],
'Barb': [{ key: 2, name: 'B', }, { key: 4, name: 'D' }],
'John': [{ key: 3, name: 'C', }, ],
}
So far my solution is this:
function matchOwners (items, owners) {
const ownersWithName = {};
for (const item of items) {
if (owners[item.owner]) {
if (ownersWithName[item.owner]) {
ownersWithName[item.owner] = [ ...ownersWithName[item.owner], item];
} else {
ownersWithName[item.owner] = [item];
}
}
}
return ownersWithName;
}
This solution works, but i feel it's too verbose. i tried to use the spread operator without the if condition, but this needs the array to exist already, otherwise i get the error ownersWithName[item.owner] is not iterable. Is there a better way to do this?
Something like (completely untested):
ownersWithName = items.reduce((result, item) => {
if (owners[item.owner]) {
if (!(item.owner in result)) {
result[item.owner] = [];
}
result[item.owner].push({key: item.key, name: item.name});
}
return result;
}, {})
You can also simply achieve this by using Array.forEach() along with the Object.keys() method.
Live Demo (Descriptive comments has been added in the below code snippet) :
// Input array
const items = [
{ key: 1, name: 'A', owner: 'Alex', },
{ key: 2, name: 'B', owner: 'Barb', },
{ key: 3, name: 'C', owner: 'John', },
{ key: 4, name: 'D', owner: 'Barb', },
{ key: 5, name: 'E', owner: 'Alex', },
];
// Input object which should be used to match.
const owners = {
'Alex': { 1: [], 5: [] },
'John': { 3: [], },
'Barb': { 2: [], 4: [] },
};
// Declare an object which will store the final result.
const resultObj = {};
// Iterating over an items array to manipulate the data and make the final result set.
items.forEach(obj => {
resultObj[obj.owner] = !resultObj[obj.owner] ? [] : resultObj[obj.owner];
Object.keys(owners[obj.owner]).forEach(key => {
if (key == obj.key) {
resultObj[obj.owner].push({
key: obj.key,
name: obj.name
});
}
});
});
// Final output
console.log(resultObj);
This question already has answers here:
group array of objects by id
(8 answers)
Closed 1 year ago.
I want to group the array of objects based on the key and concat all the grouped objects into a single array. GroupBy based on the id
example,
payload
[
{
id: 1,
name: 'a'
},
{
id: 1,
name: 'b'
},
{
id: 1,
name: 'c'
},
{
id: 2,
name: 'b'
},
{
id: 2,
name: 'c'
}
]
expected response
[
[
{
id: 1,
name: 'a'
},
{
id: 1,
name: 'b'
},
{
id: 1,
name: 'c'
}
],
[
{
id: 2,
name: 'b'
},
{
id: 2,
name: 'c'
}
]
]
All the matched elements are in the same array and all the arrays should be in a single array.
Array.redue will help
const input = [
{ id: 1, name: 'a' },
{ id: 1, name: 'b' },
{ id: 1, name: 'c' },
{ id: 2, name: 'b' },
{ id: 2, name: 'c' }
];
const output = input.reduce((acc, curr) => {
const node = acc.find(item => item.find(x => x.id === curr.id));
node ? node.push(curr) : acc.push([curr]);
return acc;
}, []);
console.log(output)
Extract the ids using Set so you have a unique set of them,
then loop over those ids and filter the original array based on it.
let objects = [
{
id: 1,
name: 'a'
},
{
id: 1,
name: 'b'
},
{
id: 1,
name: 'c'
},
{
id: 2,
name: 'b'
},
{
id: 2,
name: 'c'
}
]
let ids = [...new Set(objects.map(i => i.id))]
let result = ids.map(id => objects.filter(n => id === n.id))
console.log(result)
you can create a object with ids array by using Array.reduce method, and get the object values by Object.values
var s = [{
id: 1,
name: 'a'
},
{
id: 1,
name: 'b'
},
{
id: 1,
name: 'c'
},
{
id: 2,
name: 'b'
},
{
id: 2,
name: 'c'
}
];
//go through the input array and create a object with id's, group the values to gather
var ids = s.reduce((a, c) => {
//check object has the `id` property, if not create a property and assign empty array
if (!a[c.id])
a[c.id] = [];
//push the value into desidred object property
a[c.id].push(c)
//return the accumulator
return a;
}, {});
//get the grouped array as values
var outPut = Object.values(ids);
console.log(outPut);
1) You can easily achieve the result using Map and forEach easily
const arr = [
{
id: 1,
name: "a",
},
{
id: 1,
name: "b",
},
{
id: 1,
name: "c",
},
{
id: 2,
name: "b",
},
{
id: 2,
name: "c",
},
];
const map = new Map();
arr.forEach((o) => !map.has(o.id) ? map.set(o.id, [o]) : map.get(o.id).push(o));
const result = [...map.values()];
console.log(result);
/* This is not a part of answer. It is just to give the output full height. So IGNORE IT */
.as-console-wrapper { max-height: 100% !important; top: 0; }
2) You can also achieve the result using reduce
const arr = [
{
id: 1,
name: "a",
},
{
id: 1,
name: "b",
},
{
id: 1,
name: "c",
},
{
id: 2,
name: "b",
},
{
id: 2,
name: "c",
},
];
const result = [...arr.reduce((map, curr) => {
!map.has(curr.id) ? map.set(curr.id, [curr]) : map.get(curr.id).push(curr);
return map;
}, new Map()).values()];
console.log(result);
/* This is not a part of answer. It is just to give the output full height. So IGNORE IT */
.as-console-wrapper { max-height: 100% !important; top: 0; }
I have 2 arrays:
0: {id: 2, name: "TMA"}
1: {id: 3, name: "Hibbernate"}
0: {id: 1, name: "FB.DE"}
1: {id: 2, name: "TMA"}
2: {id: 3, name: "Hibbernate"}
3: {id: 4, name: "Event.it A"}
4: {id: 5, name: "Projket 2"}
5: {id: 6, name: "Projekt 1"}
I want to compare them and delete the objects with the id 2 and 3 cause both arrays have them and thats the similarity.
This is my Code so far:
const projectListOutput = projectsOfPersonArray.filter(project => data.includes(project));
console.log(projectListOutput);
But every time i run this projectListOutput is empty.
When using includes dont compare objects, Just build data as array of strings. Remaining code is similar to what you have.
arr1 = [
{ id: 2, name: "TMA" },
{ id: 3, name: "Hibbernate" },
];
arr2 = [
{ id: 1, name: "FB.DE" },
{ id: 2, name: "TMA" },
{ id: 3, name: "Hibbernate" },
{ id: 4, name: "Event.it A" },
{ id: 5, name: "Projket 2" },
{ id: 6, name: "Projekt 1" },
];
const data = arr1.map(({ id }) => id);
const result = arr2.filter(({ id }) => !data.includes(id));
console.log(result);
Your data array probably does not contain the exact same object references than projectsOfPersonArray. Look at the code below:
[{ foo: 'bar' }].includes({ foo: 'bar' });
// false
Objects look equal, but they don't share the same reference (= they're not the same).
It's safer to use includes with primitive values like numbers or strings. You can for example check the ids of your objects instead of the full objects.
You compare different objects, so every object is unique.
For filtering, you need to compare all properties or use a JSON string, if the order of properties is equal.
var exclude = [{ id: 2, name: "TMA" }, { id: 3, name: "Hibbernate" }],
data = [{ id: 2, name: "TMA" }, { id: 3, name: "Hibbernate" }, { id: 1, name: "FB.DE" }, { id: 2, name: "TMA" }, { id: 3, name: "Hibbernate" }, { id: 4, name: "Event.it A" }, { id: 5, name: "Projket 2" }, { id: 6, name: "Projekt 1" }],
result = data.filter(project =>
!exclude.some(item => JSON.stringify(item) === JSON.stringify(project))
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can do something similar to the next:
const source = [{
id: 1,
name: "FB.DE"
},
{
id: 2,
name: "TMA"
},
{
id: 3,
name: "Hibbernate"
},
{
id: 4,
name: "Event.it A"
},
{
id: 5,
name: "Projket 2"
},
{
id: 6,
name: "Projekt 1"
}
]
const toRemove = [{
id: 2,
name: "TMA"
},
{
id: 3,
name: "Hibbernate"
}
]
/**create object where keys is object "id" prop, and value is true**/
const toRemoveMap = toRemove.reduce((result, item) => ({
...result,
[item.id]: true
}), {})
const result = source.filter(item => !toRemoveMap[item.id])
You can make function from it:
function removeArrayDuplicates (sourceArray, duplicatesArray, accessor) {
const toRemoveMap = duplicatesArray.reduce((result, item) => ({
...result,
[item[accessor]]: true
}), {});
return sourceArray.filter(item => !toRemoveMap[item[accessor]])
}
removeArrayDuplicates(source, toRemove, 'id')
Or even better, you can make it work with a function instead of just property accessor:
function removeDuplicates (sourceArray, duplicatesArray, accessor) {
let objectSerializer = obj => obj[accessor];
if(typeof accessor === 'function') {
objectSerializer = accessor;
}
const toRemoveMap = duplicatesArray.reduce((result, item) => ({
...result,
[objectSerializer(item)]: true
}), {});
return sourceArray.filter(item => !toRemoveMap[objectSerializer(item)])
}
removeDuplicates(source, toRemove, (obj) => JSON.stringify(obj))
This function will help you merge two sorted arrays
var arr1 = [
{ id: 2, name: 'TMA' },
{ id: 3, name: 'Hibbernate' },
]
var arr2 = [
{ id: 1, name: 'FB.DE' },
{ id: 2, name: 'TMA' },
{ id: 3, name: 'Hibbernate' },
{ id: 4, name: 'Event.it A' },
{ id: 5, name: 'Projket 2' },
]
function mergeArray(array1, array2) {
var result = []
var firstArrayLen = array1.length
var secondArrayLen = array2.length
var i = 0 // index for first array
var j = 0 // index for second array
while (i < firstArrayLen || j < secondArrayLen) {
if (i === firstArrayLen) { // first array doesn't have any other members
while (j < secondArrayLen) { // we copy rest members of first array as a result
result.push(array2[j])
j++
}
} else if (j === secondArrayLen) { // second array doesn't have any other members
while (i < firstArrayLen) { // we copy the rest members of the first array to the result array
result.push(array1[i])
i++
}
} else if (array1[i].id < array2[j].id) {
result.push(array1[i])
i++
} else if (array1[i].id > array2[j].id) {
result.push(array2[j])
j++
} else {
result.push(array1[i])
i++
j++
}
}
return result
}
console.log(mergeArray(arr1,arr2));
I have 2 key maps, that I would like to iterate over. If the key is the same, then I want to use _.assign() to override the values. For example:
var keyMap1 = {
1: {
id: 1,
name: 'egg'
},
2: {
id: 2,
name: 'bacon'
}
};
var keyMap2 = {
1: {
id: 1,
quantity: 3
},
2: {
id: 2,
quantity: 2
}
};
// something like this, preferably with lodash
var result = _.compareKeys(override, keyMap1, keyMap2);
function override(obj1, obj2){
return _.assign(obj1, obj2)
}
console.log(result);
// => { 1: { id: 1, name: 'egg', quantity: 3 }, 2: { id: 2, name: 'bacon', quantity: 2 } };
If I'm understanding your request, could you not just use _.merge to do both compare and assign?
var keyMap1 = {
1: {
id: 1,
name: 'egg'
},
2: {
id: 2,
name: 'bacon'
}
};
var keyMap2 = {
1: {
id: 1,
quantity: 3
},
2: {
id: 2,
quantity: 2
}
};
var result = _.merge({}, keyMap1, keyMap2);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
I'm trying to strip the duplicate array values from my current array. And I'd like to store the fresh list (list without duplicates) into a new variable.
var names = ["Daniel","Lucas","Gwen","Henry","Jasper","Lucas","Daniel"];
const uniqueNames = [];
const namesArr = names.filter((val, id) => {
names.indexOf(val) == id; // this just returns true
});
How can I remove the duplicated names and place the non-duplicates into a new variable?
ie: uniqueNames would return...
["Daniel","Lucas","Gwen","Henry","Jasper"]
(I'm using react jsx) Thank you!
You can do it in a one-liner
const uniqueNames = Array.from(new Set(names));
// it will return a collection of unique items
Note that #Wild Widow pointed out one of your mistake - you did not use the return statement. (it sucks when we forget, but it happens!)
I will add to that that you code could be simplified and the callback could be more reusable if you take into account the third argument of the filter(a,b,c) function - where c is the array being traversed. With that said you could refactor your code as follow:
const uniqueNames = names.filter((val, id, array) => {
return array.indexOf(val) == id;
});
Also, you won't even need a return statement if you use es6
const uniqueNames = names.filter((val,id,array) => array.indexOf(val) == id);
If you want to remove duplicate values which contains same "id", You can use this.
const arr = [
{ id: 2, name: "sumit" },
{ id: 1, name: "amit" },
{ id: 3, name: "rahul" },
{ id: 4, name: "jay" },
{ id: 2, name: "ra one" },
{ id: 3, name: "alex" },
{ id: 1, name: "devid" },
{ id: 7, name: "sam" },
];
function getUnique(arr, index) {
const unique = arr
.map(e => e[index])
// store the keys of the unique objects
.map((e, i, final) => final.indexOf(e) === i && i)
// eliminate the dead keys & store unique objects
.filter(e => arr[e]).map(e => arr[e]);
return unique;
}
console.log(getUnique(arr,'id'))
Result :
[
{ id: 2, name: "sumit" },
{ id: 1, name: "amit" },
{ id: 3, name: "rahul" },
{ id: 4, name: "jay" },
{ id: 7, name: "sam" }
]
you forgot to use return statement in the filter call
const namesArr = duplicatesArray.filter(function(elem, pos) {
return duplicatesArray.indexOf(elem) == pos;
});
Since I found the code of #Infaz 's answer used somewhere and it confused me greatly, I thought I would share the refactored function.
function getUnique(array, key) {
if (typeof key !== 'function') {
const property = key;
key = function(item) { return item[property]; };
}
return Array.from(array.reduce(function(map, item) {
const k = key(item);
if (!map.has(k)) map.set(k, item);
return map;
}, new Map()).values());
}
// Example
const items = [
{ id: 2, name: "sumit" },
{ id: 1, name: "amit" },
{ id: 3, name: "rahul" },
{ id: 4, name: "jay" },
{ id: 2, name: "ra one" },
{ id: 3, name: "alex" },
{ id: 1, name: "devid" },
{ id: 7, name: "sam" },
];
console.log(getUnique(items, 'id'));
/*Output:
[
{ id: 2, name: "sumit" },
{ id: 1, name: "amit" },
{ id: 3, name: "rahul" },
{ id: 4, name: "jay" },
{ id: 7, name: "sam" }
]
*/
Also you can do this
{Array.from(new Set(yourArray.map((j) => j.location))).map((location) => (
<option value={`${location}`}>{location}</option>
))}