I have been breaking my brain for the last 2 days trying to find a solution to the problem but I can't figure it out.
I need to sort an array of arrays first numerically and then lexicographically. While a custom a < b function can solve the first, a normal array.sort() can do the second. But I have no clue how to combine them.
I have an array similar to this one:
var arr = [
[ '80', '1', '230' ],
[ '9', '1', '230' ],
[ 'Ken', '6', '100' ],
[ 'Dan', '2', '800' ],
[ 'Tom', '6', '500' ],
[ 'team10', '2', '222' ],
[ 'team9', '2', '222' ]
];
This array needs to be sorted numerically first according to the numbers in arr[n][1] (largest to smallest). Results with the same arr[n][1] value need to them be ordered numerically according to arr[n][2] (largest to smallest). And finally results with the same value [n][1] and [n][2] need to be ordered lexigographically based on arr[n][0].
The farthest I have gotten so far is this approach:
function sortArr() {
arr.sort(function(a,b) {
if (a[1] === b[1]) {
if (a[2] === b[2]) {
return b[0] < a[0];
}
return a[2]-b[2];
}
return b[1]-a[1]
});
}
While the numerical sorting works with this, the lexicographical sorting doesn't. Any help would be appreciated.
I suggest to use a chained approach with String#localeCompare for strings.
Sort order:
at index 1 desc
at index 2 desc
at index 0
not nummerical part asc
nummerical part asc
var arr = [[ '80', '1', '230' ], [ '9', '1', '230' ], [ 'Ken', '6', '100' ], [ 'Dan', '2', '800' ], [ 'Tom', '6', '500' ], [ 'team10', '2', '222' ], [ 'team9', '2', '222' ]];
arr.sort(function (a, b) {
var aa = a[0].split(/(\d+)/g),
bb = b[0].split(/(\d+)/g);
return b[1] - a[1] ||
b[2] - a[2] ||
aa[0].localeCompare(bb[0]) || aa[1] - bb[1];
});
console.log(arr);
Related
How am I able to convert the following object:
data = {
sp: [ 'A', 'B', 'C' ],
jh: [ '1', '0', 'AB' ],
oa: [ 27493, 9837, 3781 ]
}
into the following array of objects:
new_data = [
{sp: 'A', jh: '1', oa: 27493},
{sp: 'B', jh: '0', oa: 9837},
{sp: 'C', jh: 'AB', oa: 3781}
]
Assuming the arrays are all the same size, map one of them and reduce the keys using the current index.
const data = {
sp: [ 'A', 'B', 'C' ],
jh: [ '1', '0', 'AB' ],
oa: [ 27493, 9837, 3781 ]
};
let keys = Object.keys(data);
let new_data = data[keys[0]].map(( _, idx ) => keys.reduce((a, c) => ({ ...a, [c]: data[c][idx] }), {}));
console.log(new_data)
.as-console-wrapper { max-height: 100% !important; top: auto; }
You can use Object.entries to get all of the key-value pairs in the object.
You can take the length of the values of the array for the first entry as the length of the output, assuming that all of the arrays in the object are of the same length.
Then, you can map over all of the possible indexes and use Object.fromEntries to create an object with the keys from the original object and the value being the value at that index in the array for that key in the original object.
const data = {
sp: [ 'A', 'B', 'C' ],
jh: [ '1', '0', 'AB' ],
oa: [ 27493, 9837, 3781 ]
}
let entries = Object.entries(data);
let res = entries[0][1].map((_, i)=>Object.fromEntries(
entries.map(([k, v])=>[k, v[i]])));
console.log(res);
I have tried to convert the string type to numbers in array but the operators are in the way.
let outputArray = ['3', '5', '7' ,'+', '*', '9', '-' ];
numoutputArray = outputArray.map(Number);
console.log(numoutputArray)
//[ 3, 5, 7, NaN, NaN, 9, NaN ]
I wanted to get the array as [3,5,7,'+','*',9,'-'].
this way...
let outputArray = ['3', '5', '7' ,'+', '*', '9', '-' ]
numoutputArray = outputArray.map(v=>isNaN(v)?v:Number(v))
console.log( JSON.stringify( numoutputArray ))
What is the best way to add List to List in Immutable.js?
concat method is working, but another way is not working.
const a = fromJS([
{
comment: 'aaaa',
who: 'a1',
buttonInfo: ['a', 'b', 'c'],
},
{
comment: 'bb',
who: 'a2',
buttonInfo: ['a', 'b', 'c'],
},
]);
const b = fromJS([
{
comment: 'ccc',
who: 'c1',
buttonInfo: ['a', 'b'],
},
{
comment: 'ddd',
who: 'd2',
buttonInfo: ['a''],
},
]);
This is working:
a.concat(b)
But this is not working:
[...a ,...b]
// or
b.map(v => {
a.push(v);
})
you can use concat method as it said in doc:
const list1 = List([ 1, 2, 3 ]);
const list2 = List([ 4, 5, 6 ]);
const array = [ 7, 8, 9 ];
const list3 = list1.concat(list2, array);
// List [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
An ImmutableJS list has a method named concat whose behavior is the same as a normal javascript array. However, you cannot use spread syntax for an Immutable array.
Also the syntax for push is different from the normal array, push like concat with Immutable List returns a new list, your map method will look like
b.map(v => {
a = a.push(v);
})
P.S. Using the above method though will mutate your array a. You must create a new List and then push both the array contents into it if you want to use push. However concat is the best way for your case
For add List to List in Immutable.js, you can use merge method.
Example:
const a = fromJS(
[
{
comment: 'aaaa',
who: 'a1',
buttonInfo: ['a', 'b', 'c'],
},
{
comment: 'bb',
who: 'a2',
buttonInfo: ['a', 'b', 'c'],
},
]
);
const b = fromJS(
[
{
comment: 'ccc',
who: 'c1',
buttonInfo: ['a', 'b'],
},
{
comment: 'ddd',
who: 'd2',
buttonInfo: ['a''],
},
]
);
a.merge(b);
I try to use an array to iterate all posibilities of combine n element from an array:
array = ["9","0","1","2"];
For example the function combine(array,iter) with iter=2 shuld return:
["90","09","91","19","92","29","01","10","02","20","12","21","99","00","11","22"]
Parameters are define:
array: original array with all elements to combine.
iter: number of elements to result in combine with duplicates.
I try using yield, but without results, the quantity of elements are correct but, the value is wrong:
//Thank you to le_m for the code in ES6!
function* express(tokens, size) {
if (size < 1) yield [];
else
for (var item of tokens) {
for (var combination of express(tokens, size - 1)) {
yield combination.concat(item);
}
}
}
array = ["9","0","1","2"];
for (iter of express(array,2)) {
console.log(iter)
}
Console Output:
[ '9', '9' ]
[ '0', '9' ]
[ '1', '9' ]
[ '2', '9' ]
[ '9', '0' ]
[ '0', '0' ]
[ '1', '0' ]
[ '2', '0' ]
[ '9', '1' ]
[ '0', '1' ]
[ '1', '1' ]
[ '2', '1' ]
[ '9', '2' ]
[ '0', '2' ]
[ '1', '2' ]
[ '2', '2' ]
You want to generate all possible combinations of a given length. There are n^length combinations in total. To avoid the possibly huge memory requirement, I recommend using a generator function:
// Return all combinations of 'length' elements from array:
function* combine(array, length) {
if (length < 1) yield [];
else for (let element of array) {
for (let combination of combine(array, length - 1)) {
yield combination.concat(element);
}
}
}
// Example:
console.log(...combine(["9", "0", "1", "2"], 2));
I am trying to figure a way in JS to sort an array without actually changing the order of the elements but have more like a "grouping" feature.
Sample Data:
[
{group: 'test', title: 'A'},
{group: 'test', title: 'B'},
{group: 'test2', title: 'C'},
{group: 'test', title: 'D'}
]
My idea is to do an [].sort() the way that my final order is:
[
{group: 'test', title: 'A'},
{group: 'test', title: 'B'},
{group: 'test', title: 'D'},
{group: 'test2', title: 'C'}
]
Means: I did not change the order of the first two items but only switched #3 and #4 because of their group. If I'd do with a classical localeCompare, I'd end up with my groups being restored based on their value which is not what I want, their order should be kept.
EDIT: Considering the answers, I want to re-clarify that I do not want to change the order of the groups, means they should not be alphabetically sorted but instead, they should be groupped by the order they appear.
You need to provide a custom comparison function to Array.sort
var a = [
{group: 'test', title: 'A'},
{group: 'test', title: 'B'},
{group: 'test2', title: 'C'},
{group: 'test', title: 'D'}
];
function myComparisonFunction(a1, b1) {
return a1.group < b1.group ? -1 : a1.group === b1.group ? 0 : 1;
}
a.sort(myComparisonFunction);
console.log(a);
Try this:
function compare(b,c) {
if (b.title < c.title)
return -1;
if (b.title > c.title)
return 1;
return 0;
}
objs.sort(compare);
You can try with a compare function similar to this:
function comp(a, b) {
if (a.group == b.group) {
return a.title < b.title ? -1 : a.title == b.title ? 0 : 1;
}
return a.group < b.group ? -1 : 1;
}
youArray.sort(comp)
If I understood your question correctly, you want to sort on groups first, but then sort on title if your groups are the same.