Cosa ho imparato oggi? per ordinare delle stringhe che rappresentano la numerazione di un documento non possiamo ricorrere all'ordinamento alfanumerico.
Tipicamente un documento è ordinato usando un metodo per punti:
2.1.3
Quando vediamo questa numerazione traduciamo questi numeri cardinali in ordinali: di fatto leggiamo qualcosa come per esempio
terzo paragrafo del primo sottotitolo del secondo capitolo.
In più potremmo dover considerare che abbiamo casi del tipo
2.2
quindi mancanti della terza componente della numerazione in quanto questa si presuppone 0.
Normalizzare le parti che compongono la numerazione
La soluzione che ho trovato cercando risorse in internet è quella di normalizzare prima di tutto il numero di parti in modo che ne abbiamo sempre lo stesso numero da valutare.
Quindi passare da
1.3.5
2.1
5.3.5.6
10
a
1.3.5.0
5.3.5.6
2.1.0.0
10.0.0.0
Rendere ininfluente la posizione del numero aumentando il valore che lo esprime
Per evitare che 10 risulti minore di 2, come è per l'ordinamento alfanumerico, il trucco è quello di aumentare le cifre che compongono la numerazione sommando un numero più alto della cifra che ci aspettiamo essere il massimo. Per esempio sommando sempre 100 ad ogni parte otteniamo:
101.103.105.100
105.103.105.106
102.101.100.100
110.100.100.100
Quello che abbiamo, nonostante siano espressi da numeri, lo andremo a valutare come stringa in quanto semplifica di molto la comparazione e inoltre permette anche di gestire numerazioni contenenti lettere. Per esempio potremmo avere
7.1.b
7.2
che diventa
107.101.10b.100
107.102.100.100
Il codice per implementare questo algoritmo l'ho scritto così
// considerando che si possa arrivare ad una numerazione di centinaia
const templatePart = '1000';
// numerazione composta da 6 livelli di annidamento
const template = [templatePart, templatePart, templatePart, templatePart, templatePart, templatePart];
const convertForComparing = (parNumeration: string) => {
// "somma" del numero template
let parts = parNumeration.split('.').map(
(p) => templatePart.substring(0, templatePart.length - p.length) + p);
// normalizzazione del numero di parti
parts = [...parts, ...template.slice(parts.length)];
return parts.join('.');
};
const sortByParagraphNumeration = (a: Item, b: Item) => {
const pa = convertForComparing(a.par.toLowerCase() || '');
const pb = convertForComparing(b.par.toLowerCase() || '');
if (pa < pb) {
return -1;
}
if (pa > pb) {
return 1;
}
return 0;
};
La spiegazione di sicuro è manchevole di formalismo e fin troppo empirica ma nel mio caso pare funzionare a dovere.
E voi come avreste risolto?
Top comments (0)