ArrayList ordinamento
Domanda
Ho un ArrayList che contiene un gran numero di stringhe. Ha bisogno di essere ordinati in atto sulla base di tre campi (essenzialmente tre sottostringhe), che sono Nome , Età e Amt . Età è la prima stringa (posizione 0-3), Nome è secondo (3-6) e Amt è l'ultima (6-10) . L'ordine in cui questi parametri devono essere ordinati è molto importante ed è la seguente:
Prima di eseguire ascendente ordina per Nome poi fare ascendente ordina per Età (che in realtà viene prima nel substring) e poi fare discendente ordina per Amt . Questo è tutto.
Non ho questa classe
public class ArrComparer : IComparer
{
public int Compare(object x, object y)
{
string left = x.ToString();
string right = y.ToString();
string lhs = left.Substring(3, 6);
string rhs = right.Substring(3, 6);
return lhs.CompareTo(rhs);
}
}
che io uso per ordinare basata su un solo campo - Nome invocando
RecordList.Sort(new ArrComparer());
Questo mi consente di ordinare in modo corretto sulla base di tale una . La domanda è: come posso modificare questo codice per permettere a me di a ordinare in base a tutti e tre i SUBITO , nel giusto ordine e con la corretta modalità di asc / disc?
Qualsiasi codice o suggerimenti sarebbe molto apprezzato. (A proposito, nel caso in cui vi state chiedendo utilizzando List<T>
generico non è un'opzione in questo progetto).
Soluzione
Se avete bisogno di un IComparer, provare qualcosa di simile:
public class ArrComparer : IComparer
{
public int Compare(object x, object y)
{
string left = x.ToString();
string right = y.ToString();
string leftName = left.Substring([whatever]);
string rightName = right.Substring([whatever]);
// First try comparing names
int result = leftName.CompareTo(rightName);
if (result != 0)
{
return result;
}
// If that didn't work, compare ages
string leftAge = left.Substring([whatever]);
string rightAge = right.Substring([whatever]);
result = leftAge.CompareTo(rightAge);
if (result != 0)
{
return result;
}
// Finally compare amounts (descending)
string leftAmt = left.Substring([whatever]);
string rightAmt = right.Substring([whatever]);
result = -leftAmt.CompareTo(rightAmt); // Minus for descending
return result;
}
}
Altri suggerimenti
ArrayList implementa ancora IEnumerable, significa che è possibile utilizzare l'orderby semplice () e ThenBy () Estensioni in LINQ:
RecordList = new ArrayList(
RecordList.Cast<string>().OrderBy(s => s.Substring(3,3))
.ThenBy(s => int.Parse(s.Substring(0,3)))
.ThenByDescending(s => double.Parse(s.Substring(6,4)))
.ToArray());
Altri modi per esprimere questo includono la costruzione di un .OrderBy più complicata () o utilizzando un tipo anonimo per comporre la stringa come un oggetto:
RecordList = new ArrayList(
Record.Cast<string>().Select(s => new {source = s, age = int.Parse(s.Substring(0, 3)), name = s.Substring(3,3), amt = double.Parse(s.Substring(6,4))})
.OrderBy(o => o.name)
.ThenBy(o => o.age)
.ThenByDescending(o => o.amt)
.Select(o => o.source).ToArray());
mi piace questa opzione perché si è imposta per iniziare a pensare in termini di oggetti. Gioca bene le tue carte e si può saltare quell'ultimo proiezione .Select () per mantenere gli oggetti piuttosto che tornare a corde, che salverà il lavoro di dover fare tutto ciò che l'analisi su più tardi .
Se questi non sono un'opzione (forse per la stessa ragione per cui non è possibile utilizzare List
public class ArrComparer : IComparer
{
public int Compare(object x, object y)
{
int result;
string left = x.ToString();
string right = y.ToString();
string lhs1 = left.Substring(3, 3);
string rhs1 = right.Substring(3, 3);
result = lhs1.CompareTo(rhs1);
if (result == 0)
{
int lhs2 = int.Parse(left.Substring(0,3));
int rhs2 = int.Parse(right.Substring(0,3));
result = lhs2.CompareTo(rhs2);
}
if (result == 0)
{
double lhs3 = double.Parse(left.Substring(6,4));
double rhs3 = double.Parse(right.Substring(6,4));
result = rhs3.CompareTo(lhs3);
}
return result;
}
}
È possibile confrontare parte per parte:
string left = (string)x;
string right = (string)y;
string lname = left.Substring(3, 3);
string rname = right.Substring(3, 3);
int result = lname.CompareTo(rname);
if (result != 0) return result;
string lage = left.Substring(0, 3);
string rage = right.Substring(0, 3);
int result = lage.CompareTo(rage);
if (result != 0) return result;
string lamt = left.Substring(6);
string ramt = right.Substring(6);
return -lamt.CompareTo(ramt);
mi sento di raccomandare l'archiviazione dei record in un oggetto, e rendere quelli invece paragonabile.
Al fine di confrontare tutti e tre i campi con lo stesso metodo che si sta utilizzando è sufficiente estrarre tutti i tre pezzi di dati e di fare un confronto completo.
public class ArrComparer : IComparer
{
public int Compare(object x, object y)
{
string left = x.ToString();
string right = y.ToString();
// Note I assumed indexes since yours were overlapping.
string lage = left.Substring(0, 3);
string lname = left.Substring(3, 3);
string lamt = left.Substring(7, 3);
string rage = left.Substring(0, 3);
string rname = left.Substring(3, 3);
string ramt = left.Substring(7, 3);
// Compare name first, if one is greater return
int result = lname.CompareTo(rname);
if (result != 0)
return result;
// else compare age, if one is greater return
result = lage.CompareTo(rage)
if (result != 0)
return result;
// else compare amt if one is greater return
result = lamt.CompareTo(ramt)
if (result != 0)
return result;
// else they are equal
return 0;
}
}
si potrebbe spendere il vostro ArrCompare con se le dichiarazioni, come se (dx == ss) compere con altra parte della stringa. Accen deccend è meeter di ritorno -1 o 1