I am wondering if there is any way besides the very manual method of sorting the following (an example):
BBB+
BB
AA+
A-
BB-
A
B
AAA
We are trying to get the previous strings sorted as following :
AAA
AA+
A
A-
BBB+
BB
BB-
B
Is there any automatic sort that pares plus and minus putting plus first?
I am wondering if there is any way besides the very manual method of sorting the following (an example):
BBB+
BB
AA+
A-
BB-
A
B
AAA
We are trying to get the previous strings sorted as following :
AAA
AA+
A
A-
BBB+
BB
BB-
B
Is there any automatic sort that pares plus and minus putting plus first?
Share edited Jul 6, 2018 at 14:31 lealceldeiro 15k6 gold badges54 silver badges84 bronze badges asked Jul 6, 2018 at 14:22 Afshin GhaziAfshin Ghazi 2,9904 gold badges27 silver badges39 bronze badges 4-
No, but custom sorting is very simply in Javsacript. developer.mozilla/en-US/docs/Web/JavaScript/Reference/… Just scroll down to find the
pareFunction
example – Reinstate Monica Cellio Commented Jul 6, 2018 at 14:24 - Not that I know of, probably too specific a requirement. But a custom callback function to feed to Array.sort that does this should be rather easy to e up with. – C3roe Commented Jul 6, 2018 at 14:24
- 1 Standard sorting will give you ["A", "A-", "AA+", "AAA", "B", "BB", "BB-", "BBB+"], since shorter strings always e before longer strings. SO no, to get the exact same form as your output, we need a sorting function to create this form. – Shilly Commented Jul 6, 2018 at 14:25
- 1 If you are trying to order like credit reliability ratings, You could 'calculate' them and give them integer values. A is worth more than a B and a letter is worth more than + and -. And + is worth more than -. An alternative would be to actually sort each letter and such, but intuitively i think that code will be longer. – Shilly Commented Jul 6, 2018 at 14:28
6 Answers
Reset to default 3As I described in my ment, we can change the ratings into numbers so we can use basic sorting over plicated letter sorting.
const ratings = [
"BBB+",
"BB",
"AA+",
"A-",
"BB-",
"A",
"B",
"AAA"
];
// Each letter should be enough apart.
// Technically we can go for smaller numbers.
// But that can break if not carefull once we start using Moodys or S&P instead of Fitch.
// Since AA- is lower than AA, the - character has to be a negative number.
const weights = {
"A": 10000,
"B": 1000,
"C": 100,
"D": 10,
"+": 1,
"-": -1
};
const rating_values = ratings
.map( rating => ( {
rating,
"value": rating
.split( '' )
.map( character => weights[ character ] )
.reduce( ( a, b ) => a + b )
} ) );
const sorted_ratings = rating_values
.sort( ( a, b ) => b.value - a.value )
.map( obj => obj.rating );
console.log( sorted_ratings );
You could use three step sorting by splitting the letters from plus/minus sign.
For getting a sortable value for '+'
and '-'
, this approach uses a weight for these characters and takes zero for not given signs.
Then
- sort by the first character ascending,
- sort by the all characters descending,
- sort by weight ascending (
'+'
is smaller than'-'
)
var data = ['BBB+', 'BB', 'AA+', 'A-', 'BB-', 'A', 'B', 'AAA', 'AAA+', 'AAA-'];
data.sort((a, b) => {
var weight = { '+': -1, '-': 1 },
aa = a.split(/(?=[+\-])/),
bb = b.split(/(?=[+\-])/);
return aa[0][0].localeCompare(bb[0][0])
|| bb[0].localeCompare(aa[0])
|| (weight[aa[1]] || 0) - (weight[bb[1]] || 0);
});
console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You want to do something like this perhaps:
let marks = {"A": 6, "B": 1, "+": 0.5, "-": -0.5}
customGradeSort = (mark1, mark2) => {
let value1 = mark1.split("").reduce((total, e) => {
total += marks[e];
return total;
}, 0);
let value2 = mark2.split("").reduce((total, e) => {
total += marks[e];
return total;
}, 0);
return (value2 - value1)
}
const myMarks = ["BBB+", "BB","AA+","A-","BB-","A","B","AAA"]
console.log(myMarks.sort(customGradeSort));
NOTE: take value of A
such that A-
> BBB+
In this case A-
is 5.5 and BBB+
is 3.5.
I approached the problem by identyfying the sorting criteria. In this case they are in the following order: alphabetical
, length
and symbol
.
And it brought me to the simple and short solution.
It also covers cases with different letters and their count:
const input = ["BBB+", "BB", "AA+", "A-", "BB-","A","B", "AAA"];
const sorted = input.sort((a,b) => {
const [ [ aStr, aSign ], [ bStr, bSign ] ] = [a,b].map(str => str.match(/[A-Z]+|[\+|\-]/gi));
const [aSignNum, bSignNum] = [aSign, bSign].map(a => a === "+" ? 1 : a === "-" ? -1 : 0);
const alphCriteria = aStr[0].localeCompare(bStr[0]);
const countCriteria = bStr.length - aStr.length;
const signCriteria = bSignNum - aSignNum;
return alphCriteria || countCriteria || signCriteria;
});
console.log(sorted);
Knowing I'm late, I will still contribute.
What I have done:
- Create an object with weights for different characters
- Sorted accordingly
let arr = ["A", "A-", "AA+", "AAA", "B", "BB", "BB-", "BBB+"];
let weights = {
A: 100,
B: 10,
'+': 1,
'-': -1
}
function getWeightSum(str) {
let weightSum = 0;
// Iterate all characters in string
// Accumulate total weight
for (let i = 0; i < str.length; i++) {
weightSum += weights[str[i]];
}
return weightSum;
}
function stringSort(a, b) {
let aInt = getWeightSum(a);
let bInt = getWeightSum(b);
if (aInt > bInt) return -1;
else if (aInt <= bInt) return 1;
else return 0;
}
console.log(arr.sort(stringSort));
My version is similar to the one from Nina (and I simplified by stealing that answer's localeCompare
rather than my first fairly silly nested conditional operators.) But it captures a somewhat different description of each element, and uses destructuring and named values rather than array indices.
It also has a slightly different manner of handling +
/-
.
const pareRatings = (a, b) => {
// e.g. ['BBB', 'B', '+'] or ['BB', 'B', '']
const describe = r => r.match(/(([A-Z])\2*)([\-\+]?)/).slice(1)
const [base1, char1, ext1] = describe(a)
const [base2, char2, ext2] = describe(b)
return char1.localeCompare(char2) ||
base2.localeCompare(base1) ||
// Unicode: 43: '+', 44: ',', 45: '-'
((ext1 || ',').charCodeAt(0) - (ext2 || ',').charCodeAt(0))
}
const ratings = ['BBB+', 'BB', 'AA+', 'A-', 'BB-', 'A', 'B', 'AAA']
console.log(ratings.sort(pareRatings))
I prefer this technique to those that weight the letters because this way can extend to as many different letters as you like and to as many copies of each. It will not for instance sort "BBBBBBBBBBB" before "A", as many of those would, and it handles "XX-" just fine.
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744930354a4601698.html
评论列表(0条)