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);
Related
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);
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; }
I have array like this:
let arr = [
{ x: 31, y: 8 }, // get 1
{ x: 32, y: 8, monster: { is: true, id: '19216' } }, // get special
{ x: 32, y: 9 },
{ x: 32, y: 10 },
{ x: 32, y: 11 }, // get 4
{ x: 32, y: 12 },
{ x: 32, y: 13 },
{ x: 32, y: 14 },
{ x: 32, y: 15 }, // get 8
{ x: 32, y: 16 } // get last
];
what I want to achieve is to get every fourth, get special one (the one with monster object) and also last one. So the output would be
[
{x: 31, y: 8},
{x: 32, y: 8, monster: { is: true, id: '19216' } },
{x: 32, y: 11},
{x: 32, y: 15},
{x: 32, y: 16}
]
It was easy to get every fourth and last one like this:
let arrThinned = [];
for (let i = 0; i < arr.length; i = i + 4) {
arrThinned.push({
x: arr[i].x,
y: arr[i].y,
});
}
if((arr.length - 1) % 4 !== 0) {
/* add also last one if not already added */
arrThinned.push({
x: arr[arr.length - 1].x,
y: arr[arr.length - 1].y
});
};
but I can't figure out how to additionally check if there is this special one beetwen every fourth and also add it to thinnedArr array. I need to keep the order. Demo of above code.
Here, use filter
let arr = [
{ x: 31, y: 8 }, // get 1
{ x: 32, y: 8, monster: { is: true, id: '19216' } }, // get special
{ x: 32, y: 9 },
{ x: 32, y: 10 },
{ x: 32, y: 11 }, // get 4
{ x: 32, y: 12 },
{ x: 32, y: 13 },
{ x: 32, y: 14 },
{ x: 32, y: 15 }, // get 8
{ x: 32, y: 16 } // get last
];
let newArr = arr.filter((e,i,ar) => (i%4 === 0 || e.monster || i===ar.length-1));
console.log(newArr);
Used .flatMap() to sort out all required objects. A custom function based on this answer counts how many keys each object had so that if an object had more than 2 keys it was considered special.The version in demo is streamlined into one line.
/** objSize(object)
Utility that returns a given Object's number of non-enumerated property keys it
has (String and Symbol).
*/
const objSize = obj => {
let strings = Object.getOwnPropertyNames(obj).length;
let symbols = Object.getOwnPropertySymbols(obj).length;
return strings + symbols;
}
Further details about .flatMap() are commented in demo.
let array = [
{ x: 31, y: 8 }, // get 1
{ x: 32, y: 8, z: { is: true, id: '19216' } },
{ x: 32, y: 9 },
{ x: 32, y: 10 },
{ x: 32, y: 11 }, // get 4
{ x: 32, y: 12 },
{ x: 32, y: 13 },
{ x: 32, y: 14 },
{ x: 32, y: 15 }, // get 8
{ x: 32, y: 16 } // get last
];
const objSize = obj => Object.getOwnPropertyNames(obj).length + Object.getOwnPropertySymbols(obj).length;
/*
.flatMap() is an array method that is basically a
combonation of `.map()` and `.flat()`. Here it is running
a function of 4 ternary controls:
1. if current index is 0:
(idx === 0)
return [xy]
2. if current index is a factor of 4:
(idx % 4 === 0)
return [xy]
3. if current xy has more than 2 keys:
(objSize(xy) > 2)
return [xy]
4. if current index is the last:
(idx === array.length - 1)
return [xy]
5. otherwise return []
each return is an array which is flattened when the final
array is returned. Therefore an empty array is a clean
removal which means no nulls, spaces, or empty values.
*/
let result = array.flatMap((xy, idx) => xy === 0 ? [xy] : idx % 4 === 0 ? [xy] : objSize(xy) > 2 ? [xy] : idx === array.length - 1 ? [xy] : []);
console.log(JSON.stringify(result));
I've got this array of objects:
[
{x: 615, y: 293, a: 1},
{x: 340, y: 439, a: 0},
{x: 292, y: 505, a: 0}
]
Basically im trying to write a collider. I'd love to return indexes of objects that values of x and y that are equal to each other, how do i approach this?
You can write a function that iterates, via map, through the array and returns the index or a null depending on this condition (x === y) and than filter it, returning only those that are different from null
const collider = array =>
array.map( (item, index) => item.x === item.y ? index : null )
.filter( item => item !== null)
Working fiddle:
https://jsfiddle.net/c3qqmh3b/
var indexes = myArray.reduce((idxs, el, i) => {
if (el.x === el.y) {
return idxs.concat(i);
} else {
return idxs;
}
}, []);
If your myArray would be, for example:
myArray = [
{x: 615, y: 293, a: 1},
{x: 340, y: 340, a: 0},
{x: 292, y: 505, a: 0}
]
then you'll get [1] as a result (because element of index 1 has x===y)
You could just use a hashtable to check for duplicates:
const hash = {};
for(const {x, y} of array) {
if(hash[x + "|" + y])
alert("collides");
hash[x + "|" + y] = true;
}
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);