How can I use object destruction as parameter in calling a function? - javascript

I have an object like this:
let a = { x: 3, y: '3', z: 'z' };
And an array like this:
let b = [{ x: 1, y: '1'}, { x: 2, y: '2' }];
How can I do something like this:
b.push({ x, y } = a);
Instead of this:
b.push({ x: a.x, y: a.y });
// or this:
const { x, y } = a;
b.push({ x, y });

You need to return a new object with the destructured properties.
const
getXY = ({x, y}) => ({ x, y }),
a = { x: 3, y: '3', z: 'z' },
b = [{ x: 1, y: '1'}, { x: 2, y: '2' }];
b.push(getXY(a));
console.log(b);

Related

How to map a object of objects getting the key and value?

I have map called "marks" that has other maps as fields. I need to do something like a forEach loop (or a map) with this getting the key and the value of each nested map.
This is my data:
"marks" : {
"mark_01": {x: 10, y: 200},
"mark_02": {x: 200, y: 100},
...
"mark_99": {x: 1000, y: 1039}
}
What I am trying to do is:
// This is wrong but represents the main idea
const newMarks = marks.map(mark => {
// Get the mark key "mark_number"
// Change its value (x, y)
// Return an object with the same key and the new manipulated value
})
Any ideas? The resulted data has to look like this:
"marks" : {
"mark_01" : {x: 0, y: 190},
"mark_02" : {x: 190, y: 90},
...
"mark_99" : {x: 990, y: 1029}
}
Below snippet could help you
const { marks } = {
marks: {
mark_01: { x: 10, y: 200, other_if_have: 'a' },
mark_02: { x: 200, y: 100, other_if_have: 'b' },
mark_99: { x: 1000, y: 1039, other_if_have: 'c' },
},
}
const temp = Object.keys(marks).map((mark) => {
const manipulate = ({ x, y }) => ({
x: x - 10,
y: y - 10,
})
return [mark, { ...marks[mark], ...manipulate(marks[mark]) }]
})
const res = { marks: Object.fromEntries(temp) }
console.log(res)
Ref:
Object.keys() doc
Object.entries() doc
Another alternative solution:
const edited = Object.fromEntries(Object.entries(marks).map(
([k,{x,y}]) => [k,{x: x+10, y: y+10}]
));
You can check it here: https://jsfiddle.net/sandro_paganotti/ztw1exb4/13/
Could use a for...in loop:
const marks = {
"mark_01": {
x: 10,
y: 200
},
"mark_02": {
x: 200,
y: 100
},
"mark_99": {
x: 1000,
y: 1039
}
}
console.log("before", marks)
for (let i in marks) {
marks[i].x += 1;
marks[i].y += 1;
}
console.log("after", marks)
Though, you should note:
The problem with a for...in loop is that it iterates through properties in the Prototype chain. When you loop through an object with the for...in loop, you need to check if the property belongs to the object. You can do this with hasOwnProperty.
So to account for this:
const marks = {
"mark_01": {
x: 10,
y: 200
},
"mark_02": {
x: 200,
y: 100
},
"mark_99": {
x: 1000,
y: 1039
}
}
console.log("before", marks)
for (let i in marks) {
if (marks.hasOwnProperty(i)) {
marks[i].x += 1;
marks[i].y += 1;
}
}
console.log("after", marks)
This is a good article to check out for something like this.
if you have undetermined number of properties inside your object you can do nested for like that
let marks = {
"mark_01": {x: 10, y: 200, z: 300, ...},
"mark_02": {x: 200, y: 100, z: 10, ...},
"mark_99": {x: 1000, y: 1039, z: 1200, ...}
}
let newMarks = {}
for (const [key, value] of Object.entries(marks)) {
let newValues = {}
for (const [innerKey, innerValue] of Object.entries(value)) {
newValues[innerKey] = innerValue - 10
}
newMarks[key] = newValues
}
console.log(newMarks);

How to count duplicate object in JS

im trying to add counting number for duplicate in JS.
and i am completely stack in this case below.
i need to compare objects with two value (x, y) and if there are same values of (x, y) add count 1 on new objects.
is there any way to convert data to newData such as below?
const data = [
{id: 1, x: 1, y: 1},
{id: 2, x: 2, y: 2},
{id: 3, x: 1, y: 1},
]
const newData = [
{x: 1, y:1 ,count:2}
{x: 2, y:2 ,count:1}
]
use .reduce() function
const data = [
{id: 1, x: 1, y: 1},
{id: 2, x: 2, y: 2},
{id: 3, x: 1, y: 1},
]
const output = data.reduce((acc, curr) => {
curr.count = 1;
const exists = acc.find(o => o.x === curr.x && o.y === curr.y);
exists ? exists.count++ : acc.push(({ x, y, count } = curr));
return acc;
}, []);
console.log(output);
.as-console-wrapper { max-height: 100% !important; top: 0; }
One way of doing so, is to create a map with the x and y values, and increment the count accordingly, then convert the map into an array:
const data = [
{id: 1, x: 1, y: 1},
{id: 2, x: 2, y: 2},
{id: 3, x: 1, y: 1},
]
const makeXYMap = (data) => data.reduce((acc, cur) => {
const { x, y } = cur;
const entry = acc[`${x}_${y}`];
if (entry) {
acc[`${x}_${y}`] = {...entry, count: entry.count + 1};
} else {
acc[`${x}_${y}`] = { x, y, count: 1 };
}
return acc;
}, {});
const makeArray = (XYMap) => Object.values(XYMap);
console.log(makeArray(makeXYMap(data)));
Note that complexity wise, this solution is a O(N).
https://jsfiddle.net/9o35neg7/
const data = [
{ id: 1, x: 1, y: 1 },
{ id: 2, x: 2, y: 2 },
{ id: 3, x: 1, y: 1 },
// .. so on ..
];
const countedData = data.reduce((acc, { x, y }, index, array) => {
acc[`x${x}y${y}`] = {
x,
y,
count: (acc[`x${x}y${y}`] ? acc[`x${x}y${y}`].count : 0) + 1
};
return index === (array.length - 1) ? Object.values(acc) : acc;
}, {});
console.log(countedData);
Use forEach and build an object with key (made of x, y) and values (aggregate count). Get the Object.values to get the results as array.
const data = [
{id: 1, x: 1, y: 1},
{id: 2, x: 2, y: 2},
{id: 3, x: 1, y: 1},
]
const counts = (arr, res = {}) => {
arr.forEach(({x , y}) =>
res[`${x}-${y}`] = { x, y, count: (res[`${x}-${y}`]?.count ?? 0) + 1 })
return Object.values(res);
}
console.log(counts(data))

get duplicates in array of objects

I have array of objects.
let coordinates = [
{ x: 8, y: 1 },
{ x: 8, y: 3 },
{ x: 6, y: 5 },
{ x: 4, y: 6 },
{ x: 3, y: 7 },
{ x: 6, y: 5 },
{ x: 3, y: 3 },
{ x: 1, y: 4 },
{ x: 3, y: 3 }
]
I stumbled upon this blog and this stackoverflow question but it only lets me find duplicates based on one property but I want to get the duplicate objects based on x and y properties like this:
[
{ x: 6, y: 5 },
{ x: 3, y: 3 }
]
We apply filter to check the uniquness of index, say if element is duplicate it will count the initial index and the current index will be filtered out.
var coordinates = [ { x: 8, y: 1 }, { x: 6, y: 5 }, { x: 4, y: 6 }, { x: 3, y: 7 }, { x: 6, y: 5 }, { x: 3, y: 3 }, { x: 1, y: 4 }, { x: 3, y: 3 }];
var result = coordinates.filter((val, i, self)=>self.findIndex(k=>k.x==val.x && k.y == val.y)!=i);
console.log(result)
UPDATE
coordinates = [ { x: 6, y: 5 }, { x: 6, y: 5 }, { x: 6, y: 5 },{ x: 4, y: 6 }, { x: 3, y: 7 }, { x: 6, y: 5 }, { x: 3, y: 3 }, { x: 3, y: 3 }, { x: 1, y: 4 }, { x: 3, y: 3 },{ x: 6, y: 5 }];
result = coordinates.reduce((acc, elem)=>{
key = Object.values(elem).join('|');
acc.unique[key] = acc.unique[key] || [];
acc.unique[key].length >0 ? acc.duplicate[key] = elem : acc.unique[key].push(elem);
return acc;
},{unique:{},duplicate:{}});
duplicate = Object.values(result.duplicate);
unique = Object.values(result.unique);
console.log(duplicate);
console.log(unique);
All the answers are not fully correct, because they don't apply to arrays with more than 2 duplicates of the same value, i.e.:
var coordinates = [
{ x: 8, y: 1 },
{ x: 8, y: 1 },
{ x: 8, y: 1 }
]
I used JSON.stringify() and Set structure to get unique duplicates from an array. And for the output I parsed strings back to the objects.
var coordinates = [
{ x: 8, y: 1 },
{ x: 6, y: 5 },
{ x: 4, y: 6 },
{ x: 3, y: 7 },
{ x: 6, y: 5 },
{ x: 3, y: 3 },
{ x: 1, y: 4 },
{ x: 3, y: 3 },
{ x: 3, y: 3 },
]
const duplicates = new Set();
const reducer = (set, val, index, arr) => arr.findIndex(k => k.x == val.x && k.y == val.y) != index ? set.add(JSON.stringify(val)) : set
coordinates.reduce(reducer, duplicates)
console.log(Array.from(duplicates).map(el => JSON.parse(el)))
You can use reduce and another array. Inside reduce callback use x & y to create an object key and check if that key exist in accumulator object. If it exist then push tyhe value to the dupArray
let coordinates = [
{ x: 8, y: 1 },
{ x: 8, y: 3 },
{ x: 6, y: 5 },
{ x: 4, y: 6 },
{ x: 3, y: 7 },
{ x: 6, y: 5 },
{ x: 3, y: 3 },
{ x: 1, y: 4 },
{ x: 3, y: 3 }
];
let dupArray = [];
let dups = coordinates.reduce((acc, curr) => {
const crtKey = '' + curr.x + '' + curr.y;
if (!acc[crtKey]) {
acc[crtKey] = 1;
} else {
dupArray.push(curr);
}
return acc;
}, {});
console.log(dupArray)
this filters only the duplicate array Objects by iterating all the Array items and for each item, iterating the Array again, using some to check if that specific item was anywhere in the array (arr) in a location before the current one (idx1) and also comparing the current item with the checked items in the some iterator by casting both to "string"
let coordinates = [
{ x: 8, y: 1 },
{ x: 8, y: 3 },
{ x: 6, y: 5 },
{ x: 4, y: 6 },
{ x: 3, y: 7 },
{ x: 6, y: 5 },
{ x: 3, y: 3 },
{ x: 1, y: 4 },
{ x: 3, y: 3 }
]
const dups = coordinates.filter(({x, y}, idx1, arr) =>
arr.some(({x:x2,y:y2}, idx2) => idx2 < idx1 && ""+x+y == ""+x2+y2 )
)
console.log( dups )
To make the check more robust, by allowing comparison of any key, what-so-ever JSON.stringify can be used to compare the arrays (assuming all array items are Objects:
const dups = coordinates.filter((item, idx1, arr) =>
arr.some((item2, idx2) => idx2 < idx1 && JSON.stringify(item) == JSON.stringify(item2))

How to update values not present in one array of objects from another array of objects?

I have two arrays of objects which contain a huge amount of data.
The structure of these two arrays goes something like this.
arr1 = [
{x: 1, y: '2018-01-01'},
{x: 2, y: '2018-01-02'},
{x: 3, y: '2018-01-03'},
{x: 5, y: '2018-01-05'},
....
]
arr2 = [
{x: 1, y: '2018-01-01'},
{x: 2, y: '2018-01-02'},
{x: 3, y: '2018-01-03'},
{x: 4, y: '2018-01-04'},
{x: 5, y: '2018-01-05'},
{x: 6, y: '2018-01-08'}
]
I want to update arr2 in such a way that it updates the array of objects with values that are only present in arr1 and drop any values not present in arr1. Note, I want to update the original arr2 and not return a new array.
I tried iterating through individual arrays and remove values not present but not luck.
You could get a map and iterate from the end for splicing unknown items or update changed values.
var arr1 = [{ x: 1, y: '2018-01-01x' }, { x: 2, y: '2018-01-02' }, { x: 3, y: '2018-01-03' }, { x: 5, y: '2018-01-05' }],
arr2 = [{ x: 1, y: '2018-01-01' }, { x: 2, y: '2018-01-02' }, { x: 3, y: '2018-01-03' }, { x: 4, y: '2018-01-04' }, { x: 5, y: '2018-01-05' }, { x: 6, y: '2018-01-08' }],
map = arr1.reduce((m, { x, y }) => m.set(x, y), new Map),
i = arr2.length;
while (i--) {
if (map.has(arr2[i].x)) {
if (map.get(arr2[i].x) !== arr2[i].y) {
arr2[i].y = map.get(arr2[i].x);
}
} else {
arr2.splice(i, 1);
}
}
console.log(arr2);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Javascript - Counting duplicates in array of object with many fields in es6

I have object array like this.
const array = [ { x: 1, y: 2 }, { x: 3, y: 4 }, { x: 1, y: 2 }, { x: 3, y: 4 }, { x: 1, y: 2 }, { x: 3, y: 12 } ]
I want to count duplicates objects and store the count as new object field.
I found this snippet and it work great but it not exactly what i need.
const names = [{ _id: 1 }, { _id: 1}, { _id: 2}, { _id: 1}]
const result = [...names.reduce( (mp, o) => {
if (!mp.has(o._id)) mp.set(o._id, Object.assign({ count: 0 }, o));
mp.get(o._id).count++;
return mp;
}, new Map).values()];
console.log(result);
It works with object with one field _id. In my case there are two, x and y
How should I modify that code?
In brief...I would like to receive the result:
result = [ { x: 1, y: 2, count:3 }, { x: 3, y: 4, count:2 }, { x: 3, y: 12, count:1 } ]
You can use Object.values() and reduce() methods to return new array of objects.
const array = [ { x: 1, y: 2 }, { x: 3, y: 4 }, { x: 1, y: 2 }, { x: 3, y: 4 }, { x: 1, y: 2 }, { x: 3, y: 12 } ]
const result = Object.values(array.reduce((r, e) => {
let k = `${e.x}|${e.y}`;
if(!r[k]) r[k] = {...e, count: 1}
else r[k].count += 1;
return r;
}, {}))
console.log(result)
Here is the solution with Map and spread syntax ...
const array = [ { x: 1, y: 2 }, { x: 3, y: 4 }, { x: 1, y: 2 }, { x: 3, y: 4 }, { x: 1, y: 2 }, { x: 3, y: 12 } ]
const result = [...array.reduce((r, e) => {
let k = `${e.x}|${e.y}`;
if(!r.has(k)) r.set(k, {...e, count: 1})
else r.get(k).count++
return r;
}, new Map).values()]
console.log(result)
One way to do it would be to create an index mapping both x and y to the result entry:
let index = { };
let result = [ ];
const array = [ { x: 1, y: 2 }, { x: 3, y: 4 }, { x: 1, y: 2 }, { x: 3, y: 4 }, { x: 1, y: 2 }, { x: 3, y: 12 } ];
array.forEach(point => {
let key = '' + point.x + '||' + point.y;
if (key in index) {
index[key].count++;
} else {
let newEntry = { x: point.x, y: point.y, count: 1 };
index[key] = newEntry;
result.push(newEntry);
}
});
console.log(result);

Categories

Resources