I have an array as follows:
var arr1 = [{x: 0, y: 0}, {x: 10, y: 10}, {x: 20, y: 20}, {x: 30, y: 30}, {x: 40, y: 40}]
arr1 represents the data in an infotable created by a user and I have sorted arr1 in ascending order of x using .sort.
arr1.sort(function(a, b){return a.x - b.x});
When the user changes the name of the values in the infotable (arr1) from x to z or creates a new infotable with different names, I have to modify my code to sort it again.
var arr1 = [{z: 0, y: 0}, {z: 10, y: 10}, {z: 20, y: 20}, {z: 30, y: 30}, {z: 40, y: 40}]
arr1.sort(function(a, b){return a.z - b.z});
Therefore, I want my sort function to be dynamic so that I do not have to change the code when the name of the values in the array is changed or when an infotable with new names is created. I hope I got my question across clearly, any help is greatly appreciated!
You could store the key to sort by in a variable and use that variable instead. Example:
var arr1 = [{z: 0, y: 0}, {z: 10, y: 10}, {z: 20, y: 20}, {z: 30, y: 30}, {z: 40, y: 40}]
let keyToSortBy = 'z'
arr1.sort(function(a, b){return a[keyToSortBy] - b[keyToSortBy]});
If you are a fan of lodash.
import _ from "lodash"
let key = 'z' // dynamic key
_.sortBy(arr1, key);
You need to figure out a way to dynamically tell your algorithm what's the field you need to sort by. One example would be including a property in each element with the name of the field to sort. Sample:
var arr1 = [{x: 0, y: 0, sort: 'x'}, {x: 10, y: 10, sort: 'x'}]
var arr1 = [{z: 0, y: 0, sort: 'z'}, {z: 10, y: 10, sort: 'z'}]
Then, your sort function would be the same:
var sortFunction = function(a, b){return a[a['sort']] - b[b['sort']]}
arr1.sort(sortFunction);
arr2.sort(sortFunction);
Your sample data doesn't show much difference with the value sorted by either key as the results are the same for either sort.
I changed your data slightly to show the differences using the FF console.log
The sort function could be condensed by calling a function instead of the inline defined logic.
`
Test Page
</style>
</head><body>
<script>
console.clear();
var arr1 = [{z: 0, y: 40}, {z: 10, y: 30}, {z: 20, y: 20}, {z: 30, y: 10}, {z: 40, y: 0}];
console.log('original');
console.log(arr1.toSource());
console.log();
let keyToSortBy = 'z'
arr1.sort(function(a, b){return a[keyToSortBy] - b[keyToSortBy]});
console.log('original sorted by ascending "z"');
console.log(arr1.toSource());
console.log();
keyToSortBy = 'y'
arr1.sort(function(a, b){return a[keyToSortBy] - b[keyToSortBy]});
console.log('original sorted by ascending "y"');
console.log(arr1.toSource());
console.log();
</script>
</body></html>
`
Make a function that returns a function:
var arr1 = [{z: 0, y: 0}, {z: 10, y: 10}, {z: 20, y: 20}, {z: 30, y: 30}, {z: 40, y: 40}]
const sortBy = (key) => (a, b) => a[key] - b[key];
arr1.sort(sortBy('z'));
console.log(arr1);
If you need, you may "encode" the key in the array as a property (not iteratable):
var arr1 = [{z: 0, y: 0}, {z: 10, y: 10}, {z: 20, y: 20}, {z: 30, y: 30}, {z: 40, y: 40}];
arr1.sortKey = 'z';
const sortBy = (key) => (a, b) => a[key] - b[key];
arr1.sort(sortBy(arr1.sortKey));
console.log(arr1);
And last, you may create your own sort function to ALL arrays in your program:
var arr1 = [{z: 0, y: 0}, {z: 10, y: 10}, {z: 20, y: 20}, {z: 30, y: 30}, {z: 40, y: 40}];
arr1.sortKey = 'z';
Array.prototype.mySort = function() {
this.sort((a, b) => a[this.sortKey] - b[this.sortKey]);
};
arr1.mySort();
console.log(arr1);
You can add a sortByKey to the Array prototype:
Array.prototype.sortByKey = function (key) {
return this.sort((a, b) => a[key] - b[key]);
};
const arr = [
{ x: 1, y: 100 },
{ x: 100, y: 5 },
{x: 3, y: 99 },
];
console.log(arr.sortByKey('x'));
console.log(arr.sortByKey('y'));
See the example below. Every time you make a change use xzSort.
function xzSort(array){
array.sort(function(a, b){
var A = 'x' in a ? 'x' : 'z';
var B = 'x' in b ? 'x' : 'z';
return a[A] - b[B];
});
return array;
}
var a = [{z:40, y:40}, {z:10, y:10}, {z:0, y:0}, {z:20, y:20}, {z:30, y:30}];
console.log(a); console.log(xzSort(a)); a[3] = {x:10, y:15}; console.log(xzSort(a));
Related
I have a data array like this
{x: 0, y: 7.9}
{x: 1, y: 7.5}
{x: 2, y: 7.0}
{x: 3, y: 7.4}
{x: 4, y: 7.3}
{x: 5, y: 7.2}
{x: 6, y: 7.5}
{x: 7, y: 7.6}
{x: 8, y: 7.7}
{x: 9, y: 7.2}
Based on this data, how can I find out the following y?
For example, I used a library to find out this data but how could I predict based on this data
the following data
eg for the next 30 indexes
now I have this
const cleanData = helpers.cleanData(this.data.datasets[0].data);
const ordersRegression = regression.linear(cleanData);
const regressionPoints = ordersRegression.points.map(([x, y]) => {
return {x, y};
});
this.data.datasets[1].data = regressionPoints;
But now I would like to do something with the data that I have to predict the following
It's possible ?
Is there a genuine formula?
This question already has answers here:
How to remove duplicates objects in array based on 2 properties?
(6 answers)
Closed 1 year ago.
I'm storing some coordinates in an array. It looks like this:
const coords = [{x: 260, y: 60}, {x: 180, y: 0}, {x: 180, y: 240}, {x: 360, y: 120}, {x: 180, y: 60}, {x: 180, y: 60}, {x: 180, y: 60}]
How can I filter this array so the objects are unique, meaning there are no duplicates of objects with same x and y value? Expected output should be:
const coords = [{x: 260, y: 60}, {x: 180, y: 0}, {x: 180, y: 240}, {x: 360, y: 120}, {x: 180, y: 60}]
I've seen some similar solutions, but they didn't really solve this problem.
I started with the following function
const output = Object.values(
coords.reduce( (c, e) => {
if (!c[e.x]) c[e.x] = e;
return c;
}, {})
but it only returns objects with different x values, so it just completely ommits y value.
One idea is to use a Set, map the x & y into a string, and then deserialize the Set to have unique x,y's..
eg..
const coords = [{x: 260, y: 60}, {x: 180, y: 0}, {x: 180, y: 240}, {x: 360, y: 120}, {x: 180, y: 60}, {x: 180, y: 60}, {x: 180, y: 60}];
const dedup = [...new Set(coords.map(m => `${m.x}:${m.y}`))].map(m => {
const [x,y] = m.split(':').map(n => n | 0);
return {x,y};
});
console.log(dedup);
We can use Array.reduce(),
along with a Map to get the required result.
We'd add each item to the map, using the concatenated x and y values as keys, then return the values() to get de-duplicated values.
This will have complexity of O(n), so it will be efficient for large arrays.
const coords = [{x: 260, y: 60}, {x: 180, y: 0}, {x: 180, y: 240}, {x: 360, y: 120}, {x: 180, y: 60}, {x: 180, y: 60}, {x: 180, y: 60}];
const dedup = [...coords.reduce((map, { x, y }) => {
return (map.set(`${x}-${y}`, { x, y }));
}, new Map()).values()];
console.log('De-duplicated:', dedup)
.as-console-wrapper { max-height: 100% !important; top: 0; }
Or with a regular object:
const coords = [{x: 260, y: 60}, {x: 180, y: 0}, {x: 180, y: 240}, {x: 360, y: 120}, {x: 180, y: 60}, {x: 180, y: 60}, {x: 180, y: 60}];
const dedup = Object.values(coords.reduce((acc, { x, y }) => {
return { ...acc, [`${x}-${y}`]: { x, y }}
}, {}));
console.log('De-duplicated:', dedup)
.as-console-wrapper { max-height: 100% !important; top: 0; }
A pretty inefficient (O(n^2)), but flexible and straightforward solution: You first define a function that checks if two coordinates are equal. Then you filter all elements which have an equal element at a later position in the array.
const coords = [{x: 260, y: 60}, {x: 180, y: 0}, {x: 180, y: 240}, {x: 360, y: 120}, {x: 180, y: 60}, {x: 180, y: 60}, {x: 180, y: 60}]
const customUnique = (arr, isEqual) => {
// filter elements where an equal element exists at an earlier position
// thus the first element is kept
return arr.filter((a, i) => !arr.some((b, j) => i > j && isEqual(a, b)))
}
console.log(customUnique(coords, (a, b) => a.x === b.x && a.y === b.y))
You can use originalArray.reduce() with an array instead of an object, so you can make use of array.find.
const coords = [{x: 260, y: 60}, {x: 180, y: 0}, {x: 180, y: 240}, {x: 360, y: 120}, {x: 180, y: 60}, {x: 180, y: 60}, {x: 180, y: 60}]
console.log(
coords.reduce((arr, e) => {
if (!arr.find(item => item.x == e.x && item.y == e.y)) {
arr.push(e);
}
return arr;
}, [])
);
Yet another simple solution using a temporary array. However not the best as I could say:
const filteredCoords: any = [];
for(let coord of coords)
if (!filteredCoords.find((ele: { x: number; y: number; }) => ele.x == coord.x && ele.y == coord.y)){
filteredCoords.push(coord)
}
I have an array of objects like this
const ArrayOfObject = [
{x: "1622078100000", y: 1},
{x: "1622010000000", y: 1},
{x: "1622009940000", y: 6},
{x: "1622009880000", y: 4},
{x: "1622009820000", y: 2},
{x: "1622073600000", y: 1}
]
I want something like this
const ArrayOfObject = [
{x: 1622078100000, y: 1},
{x: 1622010000000, y: 1},
{x: 1622009940000, y: 6},
{x: 1622009880000, y: 4},
{x: 1622009820000, y: 2},
{x: 1622073600000, y: 1}
]
parse the x prop from string to number. How to accomplish this in Javascript ES6 or ES5?
There is no special function to do this. You literally have to map over them.
Better instead to leave them as is, and only do it when needed
const ArrayOfObject = [
{x: "1622078100000", y: 1},
{x: "1622010000000", y: 1},
{x: "1622009940000", y: 6},
{x: "1622009880000", y: 4},
{x: "1622009820000", y: 2},
{x: "1622073600000", y: 1}
]
const ArrayOfObjectUpdated = ArrayOfObject.map(item => ({...item, x: Number(item.x)}))
You can use the + unary operator to convert a string to a number, like so:
const newArr = [];
ArrayOfObject.forEach(obj => newArr.push({x: +obj.x, y: obj.y}));
see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Unary_plus
I have an array of the form:
[
{ i: 'text', layout: {x: 1, y: 0} }
{ i: 'text', layout: {x: 0, y: 0} }
{ i: 'text', layout: {x: 1, y: 1} }
]
I would like to sort the array using ramda package
I have reached so far as to sorting Y first --
const sortedY = R.sortBy(R.path(['layout', 'y']));
const temp = sortedY(originalContent);
Please suggest how I can sort x and y -
{x: 0, y: 0}
{x: 1, y: 0}
{x: 1, y: 1}
Use sortWith to sort using multiple comparators.
const xySort = R.sortWith([
R.ascend(R.path(['layout','x'])),
R.ascend(R.path(['layout','y']))
])
Looks like you want to use sortWith.
Here is an example:
var list = [
{ i: 'first', layout: {x: 1, y: 1} },
{ i: 'second', layout: {x: 1, y: 0} },
{ i: 'third', layout: {x: 0, y: 1} },
];
var xySort = R.sortWith([
R.ascend(R.path(['layout', 'x'])),
R.ascend(R.path(['layout', 'y'])),
]);
console.log(xySort(list));
I want to get an array of the values of each object I have.
I have this:
const numDataPoints = [
{
x0: {x: 807, y: 625},
x1: {x: 15, y: 20},
x2: {x: 5, y: 20}
},
{
x0: {x: 11, y: 6},
x1: {x: 16, y: 21},
x2: {x: 7, y: 22}
}
];
I want this:
[
[807, 625],
[15, 20],
[5, 20],
[11, 6],
[16, 21],
[7, 22]
]
I tried this:
numDataPoints.map((array) => array.map(axis => [axis.x, axis.y]));
but it throws this error:
Uncaught TypeError: array.map is not a function
You can use map method with Object.values and spread syntax ....
const data = [{ x0: {x: 807, y: 625}, x1: {x: 15, y: 20}, x2: {x: 5, y: 20} }, { x0: {x: 11, y: 6}, x1: {x: 16, y: 21}, x2: {x:7, y: 22} }];
const result = [].concat(...data.map(Object.values)).map(Object.values)
console.log(result)
You can use Array.map to transform each object into an array of two-element arrays and then reduce to flatten the result:
const numDataPoints = [{ x0: {x: 807, y: 625}, x1: {x: 15, y: 20},
x2: {x: 5, y: 20} }, { x0: {x: 11, y: 6}, x1: {x: 16, y: 21}, x2: {x:7, y: 22} }];
let result = numDataPoints.map(
item => Object.values(item).map(({x, y})=> [x, y]))
.reduce((arr, current) => [...arr, ...current], []);
console.log(result);
Use reduce for that - below will work for other data too as we don't hardcode any key's names here.
const res = numDataPoints.reduce((a, b) => a.concat(Object.keys(b).map(e => Object.values(b[e]))), []);
console.log(res);
<script>
const numDataPoints = [
{
x0: {
x: 807,
y: 625
},
x1: {
x: 15,
y: 20
},
x2: {
x: 5,
y: 20
}
}, {
x0: {
x: 11,
y: 6
},
x1: {
x: 16,
y: 21
},
x2: {
x: 7,
y: 22
}
}
];
</script>
You don’t have arrays in your numDataPoints array, but regular objects, so you can’t use map.
What you need is Object.values. Alternatively, to guarantee the same order of the keys x0, x1 and x2, destructure with {x0, x1, x2} and then use [x0, x1, x2].
The structure of numDataPoints suggests, that you actually want an array of two arrays, each with three [x, y] points, rather than just six [x, y] points. If you still want to flatten these sub-arrays, use concat or flatMap (currently a Stage 3 candidate, likely to become part of the ECMAScript edition finalized in June 2019).
Here are all six possibilities:
const numDataPoints = [
{
x0: {x: 807, y: 625},
x1: {x: 15, y: 20},
x2: {x: 5, y: 20}
},
{
x0: {x: 11, y: 6},
x1: {x: 16, y: 21},
x2: {x: 7, y: 22}
}
];
// Object.values, same structure
console.log(numDataPoints.map((obj) => Object.values(obj).map(({x, y}) => [x, y])));
// Object.values, flattened with concat
console.log([].concat(...numDataPoints.map((obj) => Object.values(obj).map(({x, y}) => [x, y]))));
// Object.values, flattened with flatMap
console.log(numDataPoints.flatMap((obj) => Object.values(obj).map(({x, y}) => [x, y])));
// Destructuring, same structure
console.log(numDataPoints.map(({x0, x1, x2}) => [x0, x1, x2].map(({x, y}) => [x, y])));
// Destructuring, flattened with concat
console.log([].concat(...numDataPoints.map(({x0, x1, x2}) => [x0, x1, x2].map(({x, y}) => [x, y]))));
// Destructuring, flattened with flatMap
console.log(numDataPoints.flatMap(({x0, x1, x2}) => [x0, x1, x2].map(({x, y}) => [x, y])));
You can use Object.keys to iterate over the keys within the object, like so:
let data = [{
x0: {
x: 807,
y: 625
},
x1: {
x: 15,
y: 20
},
x2: {
x: 5,
y: 20
}
}, {
x0: {
x: 11,
y: 6
},
x1: {
x: 16,
y: 21
},
x2: {
x: 7,
y: 22
}
}];
let result = data.map(obj => Object.keys(obj).map((key) => [obj[key].x, obj[key].y]));
console.log(result);
You may want to flatten the result, I'm not sure.
This is because what you get is an object, not an array. Although you could try (Es6) :
numDataPoints
.map(_ => {
return Object.values(_)
.map(({x, y}) => [x, y]);
}).reduce((acc, elem) => [...acc, ...elem], []);
The problem is that array is an object, so you have to map the keys before using another forEach.
const numDataPoints = [{ x0: {x: 807, y: 625}, x1: {x: 15, y: 20},x2: {x: 5, y: 20} }, { x0: {x: 11, y: 6}, x1: {x: 16, y: 21}, x2: {x:7, y: 22} }];
var foo = []
numDataPoints.forEach((points) =>
Object.keys(points).forEach(point =>
foo.push( [points[point].x, points[point].y] )
)
);
console.log(foo)
Here are a few different ways to get two different results (original nesting structure or flat structure) - also notice the sorting which could be a use-case for you - dictionary keys are sorted in the way they are declared (not alphanumerically):
const numDataPoints = [{ x0: {x: 807, y: 625}, x1: {x: 15, y: 20},
x2: {x: 5, y: 20} }, { x0: {x: 11, y: 6}, x1: {x: 16, y: 21}, x2: {x:7, y: 22} }];
// In case you need them sorted and in the original nesting:
console.log(
numDataPoints
.map(d => Object.keys(d).sort().map(k => [d[k].x, d[k].y]))
);
// In case you need them sorted and flattened:
console.log(
numDataPoints
.map(d => Object.keys(d).sort().map(k => [d[k].x, d[k].y]))
.reduce((a,v) => { v.forEach(value => a.push(value)); return a; }, [])
);
// In case you don't need them sorted and in the original nesting:
console.log(
numDataPoints
.map(d => Object.keys(d).map(k => [d[k].x, d[k].y]))
);
// In case you don't need them sorted and flattened:
console.log(
numDataPoints
.map(d => Object.keys(d).map(k => [d[k].x, d[k].y]))
.reduce((a,v) => { v.forEach(value => a.push(value)); return a; }, [])
);