Normalize Data in array of Objects (JavaScript) - javascript

im trying to normalize some data sitting in an array of objects.
[
{id: 1, number: 10, x: 0.3, y: 0.4, …}
{id: 2, number: 5, x: 0.5, y: 0.2, …}
{...}
{...}
{...}
]
I want to map the x and y entry's on a new value between 0 - 1250. So I get the following Array of Objects
[
{id: 1, number: 10, x: 375, y: 500, …}
{id: 2, number: 5, x: 625, y: 250, …}
{...}
{...}
{...}
]
Whats the best Practice for that?
Best,
Chris

You can use Array.map
const arr = [
{id: 1, number: 10, x: 0.3, y: 0.4},
{id: 2, number: 5, x: 0.5, y: 0.2}
];
// Use Array.map to iterate
const arr1 = arr.map(ob => {
ob.x*=1250;
ob.y*=1250;
return ob;
});
console.log(arr1);

Some thing like this with map method.
const arr = [
{id: 1, number: 10, x: 0.3, y: 0.4},
{id: 2, number: 5, x: 0.5, y: 0.2},
];
const res = arr.map(({x, y, ...rest}) => ({...rest, x: x * 1250, y: y * 1250 }));
console.log(res)

Assuming arr is your array of object. You can use map which returns new modified array.
let arr = [
{
id: 1, number: 10, x: 0.3, y: 0.4,
},
{
id: 2, number: 5, x: 0.5, y: 0.2
}
];
const normalize = (obj) => {
x = obj.x * 1250;
y = obj.y * 1250;
return {...obj, x, y};
// If you're only using mutating then
// above lines can be
// obj.x *= 1250;
// obj.y *= 1250;
// return obj;
}
// Not mutating array, output new array
const nonMutating = (arr) => {
let newRes = [];
arr.forEach(a => {
newRes.push(normalize(a));
});
return newRes;
}
console.log(nonMutating(arr));
console.log("\n");
// Mutating input array
const mutating = (arr) => {
return arr.map(a => normalize(a));
}
console.log(mutating(arr));

Related

Foreach Array Element Search for values in multidimension Array javascript

Trying to match each element of an array to a set of coordinates in a multidimensions array in the following manner:
array1= [0, 5, 4]
array2 = [
{x: 1, y: 4, name: 'A', w: 0},
{x: 2, y: 8, name: 'E', w: 4},
{x: 3, y: 1, name: 'F', w: 5}];
I am hoping to match each element of array 1 to the value of w in array 2
0 -> {x: 1, y: 4, name: 'A', w: 0}
5 -> {x: 3, y: 1, name: 'F', w: 5}
4 -> {x: 2, y: 8, name: 'E', w: 4}
I want to return :
[
{x:1, y,4}, {x:3, y:1},
{x:3, y:1}, {x:2, y:8},
...
];
You should return the required x and y coordinates as an array.
Please find a working fiddle for that.
const array1 = [0, 5, 4]
const array2 = [
{ x: 1, y: 4, name: 'A', w: 0 },
{ x: 2, y: 8, name: 'E', w: 4 },
{ x: 3, y: 1, name: 'F', w: 5 },
];
const tempArray = array1.map((item) => array2.find((node) => node.w === item));
// console.log(tempArray);
const finalArray = tempArray.map((currentNode, index, actualArray) => {
const nextIndex = index === actualArray.length - 1 ? 0 : index + 1;
return [
{ x: currentNode.x, y: currentNode.y },
{ x: actualArray[nextIndex].x, y: actualArray[nextIndex].y },
];
});
console.log(finalArray);
You can chain array filter and map to do something like this
Array.prototype.filter() to filter all elements based on the index from first array and
Array.prototype.map() to modify the object so as to only show the x and y co-ordinates
const array1 = [0, 5, 4];
const array2 = [
{ x: 1, y: 4, name: "A", index: 0 },
{ x: 2, y: 8, name: "E", index: 4 },
{ x: 3, y: 1, name: "F", index: 5 },
];
const newArr = array2.filter(x => array1.includes(x.index)).map(x => ({ x: x.x, y: x.y }));
console.log(newArr)

Summarize the frequency of array of objects

Assume I have the following array of objects.
data = [
{ x: 1, y: 1 },
{ x: 2, y: 2 },
{ x: 3, y: 3 },
{ x: 2, y: 2 },
{ x: 1, y: 1 },
{ x: 1, y: 2 },
{ x: 1, y: 1 }
]
what I need is to summarize the frequency of identical object in the array. The output will look like:
summary = [
{ x: 1, y: 1, f: 3 },
{ x: 1, y: 2, f: 1 },
{ x: 2, y: 2, f: 2 },
{ x: 3, y: 3, f: 1 }
]
For now I have this code
const summary = data.map((item, index, array) => {
return { x: item.x, y: item.y, f: array.filter(i => i === item).length };
});
But I suppose I can do better by using reduce or includes. Any ideas?
Reduce into an object whose keys uniquely represent an object, whose values are the object (with x, y, and f properties). On each iteration, increment the appropriate key's f property, or create the key on the accumulator if it doesn't exist yet:
const data = [
{ x: 1, y: 1 },
{ x: 2, y: 2 },
{ x: 3, y: 3 },
{ x: 2, y: 2 },
{ x: 1, y: 1 },
{ x: 1, y: 2 },
{ x: 1, y: 1 }
];
const countObj = data.reduce((a, obj) => {
const objString = obj.x + '_' + obj.y;
if (!a[objString]) {
a[objString] = { ...obj, f: 1 };
} else {
a[objString].f++;
}
return a;
}, {});
const output = Object.values(countObj);
console.log(output);
Don't use map - you're better off using reduce like so:
const summary = Object.values(data.reduce((a, { x, y }) => {
a[`${x}-${y}`] = a[`${x}-${y}`] || { x, y, f: 0 };
a[`${x}-${y}`].f++;
return a;
}, {}));
Object.values(data.reduce((sum, i) => {
i_str = JSON.stringify(i); // objects can't be keys
sum[i_str] = Object.assign({}, i, {f: sum[i_str] ? sum[i_str].f+1 : 1});
return sum;
}, {}));
Note:
This snippet will work on an array of any arbitrary objects, as long as they are stringifiable.
Results are not ordered, since object keys aren’t ordered. If this is an issue, sort at will.
What you’re doing, is counting the times an object exists in an array. You probably want results external to the objects, as opposed to embedded in them. Something along these lines might be more manageable, returning a mapping of descriptions of the objects to a count:
data.reduce((sum, i) => {
i_str = JSON.stringify(i); // objects can't be keys
sum[i_str] = sum[i_str] ? sum[i_str]+1 : 1;
return sum;
}, {});
A simple solution based on Array#reduce would be as detailed below:
const data = [
{ x: 1, y: 1 },
{ x: 2, y: 2 },
{ x: 3, y: 3 },
{ x: 2, y: 2 },
{ x: 1, y: 1 },
{ x: 1, y: 2 },
{ x: 1, y: 1 }
];
const summary = data.reduce((frequencySummary, item) => {
/* Find a match for current item in current list of frequency summaries */
const itemMatch = frequencySummary.find(i => i.x === item.x && i.y === item.y)
if(!itemMatch) {
/* If no match found, add a new item with inital frequency of 1 to the result */
frequencySummary.push({ ...item, f : 1 });
}
else {
/* If match found, increment the frequency count of that match */
itemMatch.f ++;
}
return frequencySummary;
}, []);
console.log(summary)
I know using reduce is probably better, but I tend to use forEach and findIndex for better readability.
var data = [
{ x: 1, y: 1 },
{ x: 2, y: 2 },
{ x: 3, y: 3 },
{ x: 2, y: 2 },
{ x: 1, y: 1 },
{ x: 1, y: 2 },
{ x: 1, y: 1 }
];
var summary = [];
data.forEach(function(d){
var idx = summary.findIndex(function(i){
return i.x === d.x && i.y === d.y;
});
if(idx < 0){
var sum = Object.assign({}, d);
sum.f = 1;
summary.push(sum);
} else {
summary[idx].f = summary[idx].f + 1;
}
});
console.log(summary);
Create nested objects. The outer object uses x values as keys, the nested object contains y values as keys, and the values are the frequencies.
data = [
{ x: 1, y: 1 },
{ x: 2, y: 2 },
{ x: 3, y: 3 },
{ x: 2, y: 2 },
{ x: 1, y: 1 },
{ x: 1, y: 2 },
{ x: 1, y: 1 }
];
const nested = data.reduce((a, {x, y}) => {
a[x] = a[x] || {};
a[x][y] = a[x][y] ? a[x][y] + 1 : 1
return a;
}, {});
const summary = [];
Object.keys(nested).forEach(x => Object.keys(nested[x]).forEach(y => summary.push({x, y, f: nested[x][y]})));
console.log(summary);
You can use reduce and Map, club the use x and y as key, on every iteration check if the same key is already present on Map than just increase f count by 1 if not than set it to 1
const data = [{ x: 1, y: 1 },{ x: 2, y: 2 },{ x: 3, y: 3 },{ x: 2, y: 2 },{ x: 1, y: 1 },{ x: 1, y: 2 },{ x: 1, y: 1 }];
const countObj = data.reduce((a, obj) => {
const objString = obj.x + '_' + obj.y;
let value = a.get(objString) || obj
let f = value && value.f || 0
a.set(objString, { ...value, f: f+1 })
return a;
}, new Map());
console.log([...countObj.values()]);

Merge objects in array with similar key

I have an array of objects:
objArray = [
{x: 1, y: 7},
{x: 2, y: 14},
{x: 1, z: 9},
{x: 2, z: 18}
{x: 1, n: 6}
{x: 2, n: 16}
]
Is there an efficient way to merge for "X" without a for loop? so that I end up with:
objArray = [
{x: 1, y: 7, z: 9, n: 6},
{x: 2, y: 14, z: 18, n: 16}
]
So look for common objArray[n]["x"] and merge all hits into one object? It's OK to modify the original array or create a new one.
I'm aware this can be done with a loop, but I'm trying to avoid too many loops for this implementation, though I'm not sure if a reduce or a filter would work for this.
You could take a Map and group by property x.
var array = [{ x: 1, y: 7 }, { x: 2, y: 14 }, { x: 1, z: 9 }, { x: 2, z: 18 }, { x: 1, n: 6 }, { x: 2, n: 16 }],
result = Array.from(
array
.reduce((m, o) => m.set(o.x, Object.assign({}, m.get(o.x), o)), new Map)
.values()
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You could use reduce method to build an object and then Object.values to get an array.
const data = [{"x":1,"y":7},{"x":2,"y":14},{"x":1,"z":9},{"x":2,"z":18},{"x":1,"n":6},{"x":2,"n":16}]
const res = data.reduce((r, {x, ...rest}) => {
if(!r[x]) r[x] = {x, ...rest}
else Object.assign(r[x], rest);
return r;
}, {})
const result = Object.values(res);
console.log(result)
You can do it with Array#reduce:
const objArray = [
{x: 1, y: 7},
{x: 2, y: 14},
{x: 1, z: 9},
{x: 2, z: 18},
{x: 1, n: 6},
{x: 2, n: 16},
]
const result = Object.values( objArray.reduce(
(p,c) => (p[c.x] = Object.assign( {}, p[c.x], c ), p ), {}
) );
console.log( result );

Array of point objects to arrays of X and Y

I have an array of point objects:
const points = [ {x: 0, y: 0 }, { x: 1, y: 1}, ...]
I want to convert them to arrays of x and y:
const x = [0, 1, ...];
const y = [0, 1, ...];
I could use 2 maps:
const x = points.map(v => v.x);
const y = points.map(v => v.y);
But that needs 2 iterations over the array. I can do a loop:
const x = [];
const y = [];
for (let i = 0; i < points.length; ++i) {
const pt = points[i];
x.push(pt.x);
y.push(pt.y);
}
That seems overly verbose and potentially slow (all those push backs).
Is there a better method?
At least you need some pushing to the wanted result sets. This solution uses an object for pushing to the right array.
const
points = [{ x: 0, y: 0 }, { x: 1, y: 1 }],
x = [],
y = [],
values = { x, y };
points.forEach(o => Object.entries(o).forEach(([k, v]) => values[k].push(v)));
console.log(x);
console.log(y);
Basically the same, but with known keys.
const
points = [{ x: 0, y: 0 }, { x: 1, y: 1 }],
x = [],
y = [],
values = { x, y },
keys = Object.keys(values);
points.forEach(o => keys.forEach(k => values[k].push(o[k])));
console.log(x);
console.log(y);
While you can do this reasonably easily, say like this:
const points = [{x: 1, y: 2}, {x: 2, y: 3}, {x: 3, y: 5}, {x: 4, y: 7}, {x: 5, y: 11}]
const {x, y} = points.reduce(
({x, y}, pt) => ({x: [...x, pt.x], y: [...y, pt.y]}),
{x: [], y: []}
)
console.log(x)
console.log(y)
there is the bigger question you need to consider of why you want to do this. The original structure is flexible and useful, and you already have it in memory. The new structures depends upon shared indices, which is often difficult to work with and can easily get out of sync. Is there a strong reason not to use the original structure?
Ok, you can do make something like that :
const points = [ {x: 0, y: 0 }, { x: 1, y: 1}];
const t = points.map(item => {
return Object.values(item);
})
const x = t[0];
const y = t[1];
console.log(x,y);
var x= [], y = [], points = [{ x: 0, y: 0 }, { x: 1, y: 10 }];
points.forEach(({x: x1, y: y1}) => (x.push(x1), y.push(y1)))
console.log(x, y)
You can use array#reduce to accumulate result in a multi-dimensional array.
const points = [ {x: 0, y: 0 }, { x: 1, y: 1}],
[x,y] = points.reduce((r,o) => {
Object.values(o).forEach((v,i) => r[i].push(v));
return r;
},[[],[]]);
console.log(x);
console.log(y);

find index of max value of associate array in jquery [duplicate]

This question already has answers here:
Find maximum value of property in object of objects
(3 answers)
Closed 5 years ago.
i have an array like this,and want to find index of maximum of value .for this sample it should return c1:
var arr={
c1:{val: 9, x: 2, y: 0}
c2:{val: 1, x: 3, y: 0}
c3:{val: 6, x: 4, y: 0}
}
var arr=[{val: 9, x: 2, y: 0},
{val: 1, x: 3, y: 0},
{val: 6, x: 4, y: 0}
];
var max_value = arr.reduce((a,b)=> (a.x+a.y+a.val) > (b.x+b.y+b.val) ? a:b )
// or if it is the index that you want :
var max_index = arr.reduce((a,b,i,_)=> (_[a].x+_[a].y+_[a].val) > (b.x+b.y+b.val) ? a:i, 0);
console.log(max_value);
console.log(max_index);
Assuming your array is
var arr = [
{val: 9, x: 2, y: 0}, {val: 1, x: 3, y: 0}, {val: 6, x: 4, y: 0},
];
You can get the max value by using Math.max.apply and map
var output = Math.max.apply( null, arr.map( c => c.val ) )
Or if it is an object (as per your latest update)
var arr = {
c1:{val: 9, x: 2, y: 0},
c2:{val: 1, x: 3, y: 0},
c3:{val: 6, x: 4, y: 0}
};
var maxValue = Math.max.apply( null, Object.values( arr ).map( c => c.val ) )
You can get the index-Of the maxValue by doing
var output = Object.keys(arr).findIndex( s => arr[s].val == maxValue );

Categories