ArrayList Сортировка - PullRequest
       11

ArrayList Сортировка

1 голос
/ 15 марта 2011

У меня есть ArrayList, который содержит большое количество строк.Его нужно отсортировать по месту на основе трех полей (в основном, трех подстрок): Имя , Возраст и Амт . Возраст - первая подстрока (позиция 0-3), Имя - вторая (3-6), а Сумма - последняя (6-10).Порядок, в котором эти параметры должны быть отсортированы, очень важен и выглядит следующим образом:

Сначала выполнить по возрастанию отсортировать по Имя ТО сделать по возрастанию Сортировка по Возраст (что на самом деле происходит раньше в подстроке), а затем сделать нисходящее сортировка по Amt .Вот и все.

У меня есть этот класс

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);
    }
}

, который я использую для сортировки на основе только одного поля - Имя путем вызова

RecordList.Sort(new ArrComparer());

Это позволяет мне правильно сортироватьна основе этого одного поля.Вопрос в том, как я могу изменить этот код, чтобы разрешить мне сортировку по всем трем AT ONCE , в правильном порядке и с использованием надлежащего режима asc / desc?

Любой код или советы могутс благодарностью.(Кстати, если вам интересно, использование generic List<T> не является вариантом в этом проекте).

Ответы [ 5 ]

6 голосов
/ 15 марта 2011

ArrayList все еще реализует IEnumerable, то есть вы можете использовать простые расширения orderby () и thenby () в 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());

Другие способы выразить это включают создание более сложного .OrderBy () или использованиеанонимный тип для составления вашей строки как объекта:

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());

Мне нравится эта опция, потому что она заставляет вас начать думать в терминах объектов.Правильно разыграйте свои карты, и вы можете пропустить эту последнюю проекцию .Select (), чтобы сохранить объекты, а не возвращаться к строкам, , что избавит вас от необходимости повторного анализа позже .

Если это не вариант (возможно, по той же причине, по которой вы не можете использовать 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;
    }
}
2 голосов
/ 15 марта 2011

Вы можете сравнить по частям:

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);
1 голос
/ 15 марта 2011

Я бы порекомендовал хранить ваши записи в объекте и делать их сопоставимыми.

Чтобы сравнить все три поля с использованием того же метода, который вы используете в настоящее время, вам просто нужно извлечь все три фрагмента данных и выполнить полное сравнение.

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;
    }
}
1 голос
/ 15 марта 2011

Если вам нужен IComparer, попробуйте что-то вроде:

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;
  }
}
0 голосов
/ 15 марта 2011

вы можете использовать свой ArrCompare, если операторы типа if (rhs == lhs) конкурируют с другой частью строки. Accen deccend - счетчик возврата -1 или 1

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...