I want to give a fixed order to an array of javascript objects and I've trying with the answer of this post but they are pointing to the value, not the keys.
fixed_order = ['group','A,'N','R']
data=[
{group: "a", A: 8, N: 6}
{group: "b", N: 4, A: 20, R: 1}
{group: "c", A: 7}
]
I've try with something like this but doesn't work.
data.sort(function (a, b) {
return fixed_order.indexOf(a.keys()) - fixed_order.indexOf(b.keys());
});
the result shoulb be something like this:
data=[
{group: "a", A: 8, N: 6}
{group: "b", A: 20, N: 4, R: 1}
{group: "c", A: 7}
]
You should not attempt to put object properties in a specific order. Objects are better thought of as unordered collections of properties. Even though modern engines implement the order defined by recent EcmaScript specifications, it is not considered good practice to make your code rely on that.
Instead, change your inner data structure from plain objects to arrays. An array is the recommended data structure when order is important.
const fixedOrder = ['group', 'A', 'N', 'R'];
const data = [
[["group", "a"], ["A", 8], ["N", 6]],
[["group", "b"], ["N", 4], ["A", 20], ["R", 1]],
[["A", 7], ["group", "c"]]
];
for (const row of data) {
row.sort((a, b) => fixedOrder.indexOf(a[0]) - fixedOrder.indexOf(b[0]));
}
console.log(data);
Related
There is sourceArray and some additionalArray. Need to add items from additionalArray to the end of sourceArray. And in result sourceArray contains all items (no create new array). The problem is items count of additionalArray may be thousands.
// example
push([], [1, 2, 3], [10, 20, 30]) // [1, 2, 3, 10, 20, 30]
push(['a', 'b'], 'x', ['z', '0']) // ['a', 'b', 'x', 'z', '0']
// my solution
function push(sourceArray, ...additionalArray) {
additionalArray.forEach((array) => {
array = Array.isArray(array) ? array : [array];
if (array.length < 1000) {
sourceArray.push.apply(sourceArray, array);
} else {
array.forEach((item) => sourceArray.push(item));
}
});
return sourceArray;
}
My question is there more elegant solution for this task?
You might find using .flat() can help you here. If you use that on additionalArray, you can then spread ... those elements into a call to .push() as arguments:
const push = (source, ...rest) => {
source.push(...rest.flat());
return source;
}
console.log(push([], [1, 2, 3], [10, 20, 30])) // [1, 2, 3, 10, 20, 30]
console.log(push(['a', 'b'], 'x', ['z', '0'])) // ['a', 'b', 'x', 'z', '0']
This does have a limitation though in that .push() can only accept a certain amount of arguments. You might hit the max argument limit and this can throw considering that your additionalArray can be large. Using a for..of loop would help with that:
const push = (source, ...rest) => {
for(const item of rest.flat())
source.push(item)
return source;
}
console.log(push([], [1, 2, 3], [10, 20, 30])) // [1, 2, 3, 10, 20, 30]
console.log(push(['a', 'b'], 'x', ['z', '0'])) // ['a', 'b', 'x', 'z', '0']
As of MDN, you can use the array spread syntax:
let vegetables = ['parsnip', 'potato']
let moreVegs = ['celery', 'beetroot']
// Merge the second array into the first one
vegetables.push(...moreVegs);
console.log(vegetables) // ['parsnip', 'potato', 'celery', 'beetroot']
I have 2 arrays:
[2, 4, -2, 4, 1, 3]
["a", "b", "c", "d", "e", "f"]
and I want them to be sorted by the numerical array:
// output
[-2, 1, 2, 3, 4, 4] // <-sorted by numerical order
["c", "e", "a", "f", "b", "d"] // sorted exactly the same order as the first array
while its actually not important if "b" or "d" comes first (they both have 4 in this example)
I found many questions about this online but none of them worked for me can anyone help me with that?
You could sort the keys of the first array based on their value. This will return an array with indices of the array sorted based on the value of numbers array. Then use map to get the sorted values based on the indices
const numbers = [2, 4, -2, 4, 1, 3],
alphabets = ["a", "b", "c", "d", "e", "f"]
const keys = Array.from(numbers.keys()).sort((a, b) => numbers[a] - numbers[b])
const sortedNumbers = keys.map(i => numbers[i]),
sortedAlphabets = keys.map(i => alphabets[i])
console.log(
sortedNumbers,
sortedAlphabets
)
A standard method is to take the indices of the key array for sorting and sort the indices as pattern for all other arrays by taking the index and the value from the key array.
At the end map the sorted arrays.
var array1 = [2, 4, -2, 4, 1, 3],
array2 = ["a", "b", "c", "d", "e", "f"],
indices = [...array1.keys()].sort((a, b) => array1[a] - array1[b]);
[array1, array2] = [array1, array2].map(a => indices.map(i => a[i]));
console.log(...array1);
console.log(...array2);
I would recommend storing the entire thing in a Map. That way, you can independently sort the first array however you want and then use those values as keys to call respective value of second array.
You can do this in a single line by associating your two arrays and then ordering the items:
const x = ["a", "b", "c", "d", "e", "f"]
const y = [2, 4, -2, 4, 1, 3]
const result = y.map((val, index)=>({x:x[index], y:val})).sort((a,b)=>a.y-b.y).map(v=>v.x)
// -> ["c", "e", "a", "f", "b", "d"]
I want to get the largest object in an array of objects, the code I'm using works fine, but I wonder if there is a better way of doing the same. This is the code I'm using.
data=[
{group: "a", A: 65, N: 20},
{group: "b", R: 52},
{group: "c", N: 20, A: 2, R: 2},
{group: "d", R: 15, N: 12},
]
len = []
for (var i in data){
len.push(Object.keys(data[i]).length)
}
for (var i in data){
if (Object.keys(data[i]).length==Math.max.apply(null, len)){
subgroups = Object.keys(data[i]).slice(1).sort();
}
}
console.log(subgroups);
I think one loop is sufficient to do this.
var data=[
{group: "a", A: 65, N: 20},
{group: "b", R: 52},
{group: "c", N: 20, A: 2, R: 2},
{group: "d", R: 15, N: 12},
],
max = Object.keys(data[0]).length,
largestObj = data[0];
data.forEach(i=>{
if(Object.keys(i).length> max){
max = Object.keys(i).length;
largestObj = i;
}
});
console.log(max);
console.log(largestObj);
An example using Array.prototype.reduce
const [biggestObject] = data.reduce(
([acc, length], entry) => {
const len = Object.keys(entry).length;
return length > len ? [acc, length] : [entry, len];
},
[{}, 0]
);
To sort the whole array seems stupid, one loop is enough using reduce function
const { element } = data.reduce((agg, element) => {
const length = Object.keys(v).length
if (length > agg.length) {
return { element, length }
}
return agg
}, { element: null, length: 0 })
You can just sort the array using the criteria you used for filling the len array.
data.sort((x, y) => {
return Object.keys(y).length - Object.keys(x).length
});
Result:
0: {group: "c", N: 20, A: 2, R: 2}
1: {group: "a", A: 65, N: 20}
2: {group: "d", R: 15, N: 12}
3: {group: "b", R: 52}
Application of 'sortBy' producing unexpected results.
I've gotta be doing something stoopid. This is such a basic operation.
const input = [4,3,2,1];
const sort = list => R.sortBy(R.ascend(R.identity))(list);
console.log(sort(input)); // [ 4, 3, 2, 1 ]
I would expect the output of the 'console.log' invocation to be [ 1, 2, 3, 4 ], but it is not: the output is [ 4, 3, 2, 1 ], same as the input. What am I doing wrong?
As pointed out by Aadit M Shah in the comments you're not using sortBy correctly.
Here's quick overview of how to sort in Ramda:
sort
Returns a copy of the list, sorted according to the comparator function, which should accept two values at a time and return a negative number if the first value is smaller, a positive number if it's larger, and zero if they are equal.
One case use subtract to sort in ascending order:
sort(subtract, [4, 1, 2, 3]);
//=> [1, 2, 3, 4]
Or to sort in descending, just flip it:
sort(flip(subtract), [4, 1, 2, 3]);
//=> [4, 3, 2, 1]
sort simply expects a function that can accept two parameters which can be compared with < or >.
So how would you sort an array of strings? Strings can be compared with < or > but using subtract wouldn't make sense. This is where ascend (or descend) can be useful:
Makes an ascending comparator function out of a function that returns a value that can be compared with < and >.
sort(ascend(identity), ["b", "a", "B", "A"]);
//=> ["A", "B", "a", "b"]
And if you want to make a case insensitive comparison:
sort(ascend(toLower), ["b", "a", "B", "A"]);
//=> ["a", "A", "b", "B"]
sortBy
As we saw, sort expects that you supply it with a function that accepts two parameters that can be compared together using < or >. Numbers and strings can be compared with these operators so if you can give them to Ramda directly then:
sortBy(identity, [4, 1, 2, 3]);
//=> [1, 2, 3, 4]
is the same as:
sort(subtract, [4, 1, 2, 3]);
//=> [1, 2, 3, 4]
However as far as I can tell, sortBy will always sort things in ascending order.
sortWith
You use sortWith when you can have multiple sort criteria:
Sort by age in ascending order
Sort by name in descending order
sortWith([ascend(prop('age')), descend(prop('name'))], [
{age: 40, name: 'John'},
{age: 40, name: 'Zack'},
{age: 10, name: 'Liam'},
{age: 20, name: 'Bill'}
]);
//=> [
//=> {age: 10, name: "Liam"},
//=> {age: 20, name: "Bill"},
//=> {age: 40, name: "Zack"},
//=> {age: 40, name: "John"}
//=> ]
I have a bubble chart that I'm trying to add formatted ticks to. I also have the array that contains the strings I want to replace the numbered ticks with. An example of how my array will look like is this: ["A", "B", "C", "D"]. This array will vary in length and values on run time, but it will still contain strings. Preformatted ticks will range from 1 - length of array. 1 will be replaced with "A", 2 will be replaced with "B" and so forth. Because the array is only known during run time, I cannot do this:
hAxis: {
ticks: [
{v: 1, f: 'A'},
{v: 2, f: 'B'},
{v: 3, f: 'C'},
{v: 4, f: 'D'}
]
},
How can I output the ticks in the correct format? I've tried using a for-loop to mimic the style of the ticks format, but I am not doing it correctly.
Try this:
var input = ["A", "B", "C", "D"];
var ticks = input.map(function(item, index) {
return { v: index + 1, f: item };
});
console.log(ticks);