it-swarm.com.ru

Сортировать смешанный буквенно-цифровой массив

У меня есть смешанный массив, который мне нужно отсортировать по алфавиту, а затем по цифре

[A1, A10, A11, A12, A2, A3, A4, B10, B2, F1, F12, F3]

Как мне отсортировать это так:

[A1, A2, A3, A4, A10, A11, A12, B2, B10, F1, F3, F12]

Я пытался 

arr.sort(function(a,b) {return a - b});

но это сортирует только по алфавиту. Можно ли это сделать с помощью прямого JavaScript или jQuery?

42
solefald

var reA = /[^a-zA-Z]/g;
var reN = /[^0-9]/g;

function sortAlphaNum(a, b) {
  var aA = a.replace(reA, "");
  var bA = b.replace(reA, "");
  if (aA === bA) {
    var aN = parseInt(a.replace(reN, ""), 10);
    var bN = parseInt(b.replace(reN, ""), 10);
    return aN === bN ? 0 : aN > bN ? 1 : -1;
  } else {
    return aA > bA ? 1 : -1;
  }
}
console.log(
["A1", "A10", "A11", "A12", "A2", "A3", "A4", "B10", "B2", "F1", "F12", "F3"].sort(sortAlphaNum)
)

72
epascarello
const sortAlphaNum = (a, b) => a.localeCompare(b, 'en', { numeric: true })`

Использование:

const sortAlphaNum = (a, b) => a.localeCompare(b, 'en', { numeric: true })
console.log(['A1', 'A10', 'A11', 'A12', 'A2', 'A3', 'A4', 'B10', 'B2', 'F1', 'F12', 'F3'].sort(sortAlphaNum))

Дает:

["A1", "A2", "A3", "A4", "A10", "A11", "A12", "B2", "B10", "F1", "F3", "F12"]

Возможно, вам придется изменить аргумент 'en' на ваш язык или определить программно, но это работает для английских строк.

Кроме того, localeCompare не всегда поддерживается супер, но если ваш переход с babel это не будет проблемой

16
Jon Wyatt

У меня была похожая ситуация, но я имел комбинацию буквенно-цифровых и числовых значений, и мне нужно было сначала отсортировать все числовые значения, а затем буквенно-цифровые, поэтому:

A10
1
5
A9
2
B3
A2

нужно стать:

1
2
5
A2
A9
A10
B3

Я смог использовать предоставленный алгоритм и взломать его, чтобы выполнить это:

var reA = /[^a-zA-Z]/g;
var reN = /[^0-9]/g;
function sortAlphaNum(a,b) {
    var AInt = parseInt(a, 10);
    var BInt = parseInt(b, 10);

    if(isNaN(AInt) && isNaN(BInt)){
        var aA = a.replace(reA, "");
        var bA = b.replace(reA, "");
        if(aA === bA) {
            var aN = parseInt(a.replace(reN, ""), 10);
            var bN = parseInt(b.replace(reN, ""), 10);
            return aN === bN ? 0 : aN > bN ? 1 : -1;
        } else {
            return aA > bA ? 1 : -1;
        }
    }else if(isNaN(AInt)){//A is not an Int
        return 1;//to make alphanumeric sort first return -1 here
    }else if(isNaN(BInt)){//B is not an Int
        return -1;//to make alphanumeric sort first return 1 here
    }else{
        return AInt > BInt ? 1 : -1;
    }
}
var newlist = ["A1", 1, "A10", "A11", "A12", 5, 3, 10, 2, "A2", "A3", "A4", "B10", "B2", "F1", "F12", "F3"].sort(sortAlphaNum);
7
cmcculloh
var a1 =["A1", "A10", "A11", "A12", "A2", "A3", "A4", "B10", "B2", "F1", "F12", "F3"];

var a2 = a1.sort(function(a,b){
    var charPart = [a.substring(0,1), b.substring(0,1)],
        numPart = [a.substring(1)*1, b.substring(1)*1];

    if(charPart[0] < charPart[1]) return -1;
    else if(charPart[0] > charPart[1]) return 1;
    else{ //(charPart[0] == charPart[1]){
        if(numPart[0] < numPart[1]) return -1;
        else if(numPart[0] > numPart[1]) return 1;
        return 0;
    }
});

$('#r').html(a2.toString())

http://jsfiddle.net/8fRsD/

3
Josiah Ruddell

Это может сделать это:

function parseItem (item) {
  const [, stringPart = '', numberPart = 0] = /(^[a-zA-Z]*)(\d*)$/.exec(item) || [];
  return [stringPart, numberPart];
}

function sort (array) {
  return array.sort((a, b) => {
    const [stringA, numberA] = parseItem(a);
    const [stringB, numberB] = parseItem(b);
    const comparison = stringA.localeCompare(stringB);
    return comparison === 0 ? Number(numberA) - Number(numberB) : comparison;
  });
}

console.log(sort(['A1', 'A10', 'A11', 'A12', 'A2', 'A3', 'A4', 'B10', 'B2', 'F1', 'F12', 'F3']))
console.log(sort(['a25b', 'ab', 'a37b']))

3
Jan

Единственная проблема с приведенным выше решением состояла в том, что логика не работала, когда числовые данные были одинаковыми, а алфавиты изменялись, например 28AB, 28PQR, 28HBC . Вот модифицированный код.

var reA = /[^a-zA-Z]/g;
    var reN = /[^0-9]/g;
    var AInt = parseInt(a, 10);
    var BInt = parseInt(b, 10);
    if(isNaN(AInt) && isNaN(BInt)){
        var aA = a.replace(reA, "");
        var bA = b.replace(reA, "");
        if(aA === bA) {
            var aN = parseInt(a.replace(reN, ""), 10);
            var bN = parseInt(b.replace(reN, ""), 10);
            alert("in if "+aN+" : "+bN);
            return aN === bN ? 0 : aN > bN ? 1 : -1;
        } else {
            return aA > bA ? 1 : -1;
        }
    }else if(isNaN(AInt)){//A is not an Int
        return 1;//to make alphanumeric sort first return 1 here
    }else if(isNaN(BInt)){//B is not an Int
        return -1;//to make alphanumeric sort first return -1 here
    }else if(AInt == BInt) {
        var aA = a.replace(reA, "");
        var bA = b.replace(reA, "");
        return aA > bA ? 1 : -1;
    }
    else {
        return AInt > BInt ? 1 : -1;
    }
2
Jarna Kantaria

Добавление к принятому ответу от epascarello, так как я не могу это комментировать. Я все еще новичок здесь .. Когда у одного из strinngs нет номера, оригинальный ответ не будет работать. Например, A и A10 не будут отсортированы в этом порядке. Следовательно, вы можете захотеть вернуться к нормальной сортировке в этом случае.

var reA = /[^a-zA-Z]/g;
var reN = /[^0-9]/g;
function sortAlphaNum(a,b) {
    var aA = a.replace(reA, "");
    var bA = b.replace(reA, "");
    if(aA === bA) {
      var aN = parseInt(a.replace(reN, ""), 10);
      var bN = parseInt(b.replace(reN, ""), 10);
      if(isNaN(bN) || isNaN(bN)){
        return  a > b ? 1 : -1;
      }
      return aN === bN ? 0 : aN > bN ? 1 : -1;
    } else {
     return aA > bA ? 1 : -1;
    }
 }
 ["A1", "A10", "A11", "A12", "A2", "A3", "A4", "B10", "B2", "F1", "F12","F3"].sort(sortAlphaNum);`
1
SunnyPenguin

Простой способ сделать это - использовать метод localeCompare () JavaScripthttps://www.w3schools.com/jsref/jsref_localecompare.asp

Пример: 

export const sortAlphaNumeric = (a, b) => {
    // convert to strings and force lowercase
    a = typeof a === 'string' ? a.toLowerCase() : a.toString();
    b = typeof b === 'string' ? b.toLowerCase() : b.toString();

    return a.localeCompare(b);
};

Ожидаемое поведение:

1000X Radonius Maximus
10X Radonius
200X Radonius
20X Radonius
20X Radonius Prime
30X Radonius
40X Radonius
Allegia 50 Clasteron
Allegia 500 Clasteron
Allegia 50B Clasteron
Allegia 51 Clasteron
Allegia 6R Clasteron
Alpha 100
Alpha 2
Alpha 200
Alpha 2A
Alpha 2A-8000
Alpha 2A-900
Callisto Morphamax
Callisto Morphamax 500
Callisto Morphamax 5000
Callisto Morphamax 600
Callisto Morphamax 6000 SE
Callisto Morphamax 6000 SE2
Callisto Morphamax 700
Callisto Morphamax 7000
Xiph Xlater 10000
Xiph Xlater 2000
Xiph Xlater 300
Xiph Xlater 40
Xiph Xlater 5
Xiph Xlater 50
Xiph Xlater 500
Xiph Xlater 5000
Xiph Xlater 58
0
Mitali Bhokare

Вот обновление ES6 TypeScript к этому ответу.

export function SortAlphaNum(a: string, b: string) {
const reA = /[^a-zA-Z]/g;
const reN = /[^0-9]/g;
const aA = a.replace(reA, "");
const bA = b.replace(reA, "");
if (aA === bA) {
    const aN = parseInt(a.replace(reN, ""), 10);
    const bN = parseInt(b.replace(reN, ""), 10);
    return aN === bN ? 0 : aN > bN ? 1 : -1;
} else {
    return aA > bA ? 1 : -1;
}

}

0
Devin Prejean

Вы можете использовать Intl.Collator

Он имеет преимущества в производительности по сравнению с localeCompareЧитать здесь

Совместимость браузера (Все браузеры его поддерживают) 

let arr = ["A1", "A10", "A11", "A12", "A2", "A3", "A4", "B10", "B2", "F1", "F12", "F3"]

let op = arr.sort(new Intl.Collator('en',{numeric:true, sensitivity:'accent'}).compare)

console.log(op)

0
Code Maniac

Я решил вышеуказанную проблему сортировки с помощью скрипта ниже

arrVals.sort(function(a, b){
    //return b.text - a.text;
    var AInt = parseInt(a.text, 10);
    var BInt = parseInt(b.text, 10);

    if ($.isNumeric(a.text) == false && $.isNumeric(b.text) == false) {
        var aA = a.text
        var bA = b.text;
        return aA > bA ? 1 : -1;
    } else if ($.isNumeric(a.text) == false) {  // A is not an Int
        return 1;    // to make alphanumeric sort first return -1 here
    } else if ($.isNumeric(b.text) == false) {  // B is not an Int
        return -1;   // to make alphanumeric sort first return 1 here
    } else {
        return AInt < BInt ? 1 : -1;
    }
});

Это хорошо работает для хорошо смешанного массива. :)

Спасибо.

0
Seema
alphaNumericCompare(a, b) {

    let ax = [], bx = [];

    a.replace(/(\d+)|(\D+)/g, function (_, $1, $2) { ax.Push([$1 || Infinity, $2 || '']) });
    b.replace(/(\d+)|(\D+)/g, function (_, $1, $2) { bx.Push([$1 || Infinity, $2 || '']) });

    while (ax.length && bx.length) {
       let an = ax.shift();
       let bn = bx.shift();
       let nn = (an[0] - bn[0]) || an[1].localeCompare(bn[1]);
       if (nn) {
         return nn;
       }
     }
     return ax.length - bx.length;
}
0
hitesh kaushik