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).

È stato utile?

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 ), è facile da modificare il metodo di confronto esistente in questo modo:

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

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top