Domanda

Ho un elenco di oggetti che desidero ordinare in base a un campo attr di tipo stringa.Ho provato a usare -

list.sort(function (a, b) {
    return a.attr - b.attr
})

ma l'ho trovato - non sembra funzionare con le stringhe in JavaScript.Come posso ordinare un elenco di oggetti in base a un attributo con tipo stringa?

È stato utile?

Soluzione

Utilizzo String.prototype.localeCompare a secondo il tuo esempio:

list.sort(function (a, b) {
    return ('' + a.attr).localeCompare(b.attr);
})

Forziamo a.attr ad essere una stringa per evitare eccezioni. localeCompare è stato supportato a partire da Internet Explorer 6 e Firefox 1.Potresti anche vedere il seguente codice utilizzato che non rispetta una locale:

if (item1.attr < item2.attr)
  return -1;
if ( item1.attr > item2.attr)
  return 1;
return 0;

Altri suggerimenti

Una risposta aggiornata (ottobre 2014)

Ero davvero infastidito da questo ordinamento naturale delle stringhe, quindi ho impiegato un po' di tempo per indagare su questo problema.Spero che aiuti.

Per farla breve

localeCompare() il supporto dei personaggi è tosto, usalo e basta.Come sottolineato da Shog9, la risposta alla tua domanda è:

return item1.attr.localeCompare(item2.attr);

Bug rilevati in tutte le implementazioni javascript personalizzate dell'"ordinamento di stringhe naturali".

Ci sono un sacco di implementazioni personalizzate là fuori, che cercano di fare un confronto tra stringhe più precisamente chiamato "ordinamento naturale delle stringhe"

"Giocando" con queste implementazioni, ho sempre notato qualche strana scelta di "ordinamento naturale", o meglio errori (o omissioni nel migliore dei casi).

In genere, i caratteri speciali (spazio, trattino, e commerciale, parentesi e così via) non vengono elaborati correttamente.

Li troverai quindi mescolati in posti diversi, in genere potrebbero essere:

  • alcuni saranno compresi tra la "Z" maiuscola e la "a" minuscola
  • alcuni saranno compresi tra il "9" e la "A" maiuscola
  • alcuni saranno dopo la "z" minuscola

Quando ci si aspetterebbe che i caratteri speciali fossero tutti "raggruppati" insieme in un unico posto, ad eccezione forse del carattere speciale spazio (che sarebbe sempre il primo carattere).Cioè, o tutto prima dei numeri, o tutto tra numeri e lettere (minuscole e maiuscole sono "insieme" uno dopo l'altro), o tutto dopo le lettere.

La mia conclusione è che non riescono tutti a fornire un ordine coerente quando inizio ad aggiungere caratteri appena insoliti (ad es.caratteri con segni diacritici o caratteri come trattino, punto esclamativo e così via).

Ricerca sulle implementazioni personalizzate:

Implementazioni native dell'"ordinamento naturale delle stringhe" dei browser tramite localeCompare()

localeCompare() l'implementazione più vecchia (senza gli argomenti locali e opzioni) è supportata da IE6+, vedere http://msdn.microsoft.com/en-us/library/ie/s4esdbwz(v=vs.94).aspx (scorrere verso il basso fino al metodo localeCompare()).L'integrato localeCompare() Il metodo fa un lavoro molto migliore nell'ordinamento, anche nei caratteri internazionali e speciali.L'unico problema è usare il localeCompare() il metodo è quello "le impostazioni locali e l'ordinamento utilizzati dipendono interamente dall'implementazione".In altre parole, quando si utilizza localeCompare come stringOne.localeCompare(stringTwo):Firefox, Safari, Chrome e IE hanno un diverso ordinamento per le stringhe.

Ricerca sulle implementazioni native del browser:

Difficoltà di "ordinamento naturale delle stringhe"

Implementare un algoritmo solido (ovvero:coerente ma che copra anche una vasta gamma di personaggi) è un compito molto arduo.UTF8 contiene più di 2000 caratteri & copre più di 120 script (lingue).Infine, ci sono alcune specifiche per queste attività, si chiama "Algoritmo di collazione Unicode", che può essere trovato su http://www.unicode.org/reports/tr10/ .Puoi trovare maggiori informazioni a riguardo in questa domanda che ho postato https://softwareengineering.stackexchange.com/questions/257286/is-there-any-lingual-agnostic-specification-for-string-natural-sorting-order

Conclusione finale

Quindi, considerando l'attuale livello di supporto fornito dalle implementazioni personalizzate di Javascript in cui mi sono imbattuto, probabilmente non vedremo mai nulla che si avvicini al supporto di tutti questi caratteri e script (lingue).Quindi preferirei utilizzare il metodo localeCompare() nativo del browser.Sì, ha lo svantaggio di non essere coerente tra i browser, ma i test di base mostrano che copre una gamma molto più ampia di caratteri, consentendo un ordinamento solido e significativo.

Quindi come sottolineato da Shog9, la risposta alla tua domanda è:

return item1.attr.localeCompare(item2.attr);

Ulteriori letture:

Grazie alla bella risposta di Shog9, che mi ha messo nella direzione "giusta", credo

Risposta (in ECMAScript moderno)

list.sort((a, b) => (a.attr > b.attr) - (a.attr < b.attr))

O

list.sort((a, b) => +(a.attr > b.attr) || -(a.attr < b.attr))

Descrizione

Convertendo un valore booleano in un numero si ottiene quanto segue:

  • true -> 1
  • false -> 0

Consideriamo tre possibili modelli:

  • x è maggiore di y: (x > y) - (y < x) -> 1 - 0 -> 1
  • x è uguale a y: (x > y) - (y < x) -> 0 - 0 -> 0
  • x è minore di y: (x > y) - (y < x) -> 0 - 1 -> -1

(Alternativa)

  • x è maggiore di y: +(x > y) || -(x < y) -> 1 || 0 -> 1
  • x è uguale a y: +(x > y) || -(x < y) -> 0 || 0 -> 0
  • x è minore di y: +(x > y) || -(x < y) -> 0 || -1 -> -1

Quindi queste logiche sono equivalenti alle tipiche funzioni di comparazione di ordinamento.

if (x == y) {
    return 0;
}
return x > y ? 1 : -1;

Dovresti usare > o < e == qui.Quindi la soluzione sarebbe:

list.sort(function(item1, item2) {
    var val1 = item1.attr,
        val2 = item2.attr;
    if (val1 == val2) return 0;
    if (val1 > val2) return 1;
    if (val1 < val2) return -1;
});

Mi sono preoccupato a lungo di questo, quindi alla fine ho fatto delle ricerche e ti ho dato questa lunga ragione sul perché le cose sono come sono.

Dal spec:

Section 11.9.4   The Strict Equals Operator ( === )

The production EqualityExpression : EqualityExpression === RelationalExpression
is evaluated as follows: 
- Let lref be the result of evaluating EqualityExpression.
- Let lval be GetValue(lref).
- Let rref be the result of evaluating RelationalExpression.
- Let rval be GetValue(rref).
- Return the result of performing the strict equality comparison 
  rval === lval. (See 11.9.6)

Quindi ora passiamo all'11.9.6

11.9.6   The Strict Equality Comparison Algorithm

The comparison x === y, where x and y are values, produces true or false. 
Such a comparison is performed as follows: 
- If Type(x) is different from Type(y), return false.
- If Type(x) is Undefined, return true.
- If Type(x) is Null, return true.
- If Type(x) is Number, then
...
- If Type(x) is String, then return true if x and y are exactly the 
  same sequence of characters (same length and same characters in 
  corresponding positions); otherwise, return false.

Questo è tutto. L'operatore triplo uguale applicato alle stringhe restituisce vero se e solo se gli argomenti sono esattamente le stesse stringhe (stessa lunghezza e stessi caratteri nelle posizioni corrispondenti).

COSÌ === funzionerà nei casi in cui proviamo a confrontare stringhe che potrebbero essere arrivate da fonti diverse, ma che sappiamo che alla fine avranno gli stessi valori: uno scenario abbastanza comune per le stringhe in linea nel nostro codice.Ad esempio, se abbiamo una variabile denominata connection_state, e desideriamo sapere quale dei seguenti stati ['connecting', 'connected', 'disconnecting', 'disconnected'] è presente in questo momento, possiamo utilizzare direttamente il file ===.

Ma c'è di più.Appena sopra l'11.9.4 c'è una breve nota:

NOTE 4     
  Comparison of Strings uses a simple equality test on sequences of code 
  unit values. There is no attempt to use the more complex, semantically oriented
  definitions of character or string equality and collating order defined in the 
  Unicode specification. Therefore Strings values that are canonically equal
  according to the Unicode standard could test as unequal. In effect this 
  algorithm assumes that both Strings are already in normalized form.

Hmm.E adesso?Le stringhe ottenute esternamente possono, e molto probabilmente lo saranno, essere strane unicodey e gentili === non renderà loro giustizia.Arriva localeCompare Al salvataggio:

15.5.4.9   String.prototype.localeCompare (that)
    ...
    The actual return values are implementation-defined to permit implementers 
    to encode additional information in the value, but the function is required 
    to define a total ordering on all Strings and to return 0 when comparing
    Strings that are considered canonically equivalent by the Unicode standard. 

Possiamo andare a casa adesso.

tl; dottor;

Per confrontare le stringhe in JavaScript, utilizzare localeCompare;se sai che le stringhe non hanno componenti non ASCII perché sono, ad esempio, costanti interne del programma, allora === funziona anche.

Funzione freccia ternaria annidata

(a,b) => (a < b ? -1 : a > b ? 1 : 0)

Nell'operazione nella domanda iniziale, stai eseguendo la seguente operazione:

item1.attr - item2.attr

Quindi, supponendo che siano numeri (ad es.item1.attr = "1", item2.attr = "2") È comunque possibile utilizzare l'operatore "===" (o altri valutatori rigorosi) a condizione che si assicuri il tipo.Quanto segue dovrebbe funzionare:

return parseInt(item1.attr) - parseInt(item2.attr);

Se sono alphaNumeric, usa localCompare().

list.sort(function(item1, item2){
    return +(item1.attr > item2.attr) || +(item1.attr === item2.attr) - 1;
}) 

Come funzionano i campioni:

+('aaa'>'bbb')||+('aaa'==='bbb')-1
+(false)||+(false)-1
0||0-1
-1

+('bbb'>'aaa')||+('bbb'==='aaa')-1
+(true)||+(false)-1
1||0-1
1

+('aaa'>'aaa')||+('aaa'==='aaa')-1
+(false)||+(true)-1
0||1-1
0
<!doctype html>
<html>
<body>
<p id = "myString">zyxtspqnmdba</p>
<p id = "orderedString"></p>
<script>
var myString = document.getElementById("myString").innerHTML;
orderString(myString);
function orderString(str) {
    var i = 0;
    var myArray = str.split("");
    while (i < str.length){
        var j = i + 1;
        while (j < str.length) {
            if (myArray[j] < myArray[i]){
                var temp = myArray[i];
                myArray[i] = myArray[j];
                myArray[j] = temp;
            }
            j++;
        }
        i++;
    }
    var newString = myArray.join("");
    document.getElementById("orderedString").innerHTML = newString;
}
</script>
</body>
</html>
var str = ['v','a','da','c','k','l']
var b = str.join('').split('').sort().reverse().join('')
console.log(b)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top