C # - сортировка ArrayList строк - PullRequest
1 голос
/ 03 апреля 2011

У меня есть ArrayList строк, которые выглядят так, как показано ниже, я хотел бы вывести новый ArrayList, отсортированный определенным образом. Но не уверен в хорошем способе сортировки. Помощь будет по достоинству оценена!

Оригинал (может быть в произвольном порядке):

1:1
0:0
0:1
2:1
1:0
2:0

Выход:

2:0
2:1
1:0
1:1
0:0
0:1

Ответы [ 3 ]

4 голосов
/ 03 апреля 2011

Хотя K Иванов имеет правильную идею , вот версия, которая, возможно, проще для глаз:

// Not sure what to call the "n:n" groupings.  Assume
// original is in an ArrayList named "pairs".
IEnumerable<string> sortedPairs =
    from pair in pairs.Cast<string>()
    let parts = pair.Split(':')
    let parsed = new { 
        Left = Int32.Parse(parts[0]), 
        Right = Int32.Parse(parts[1]),
    }
    orderby parsed.Left descending, parsed.Right
    select pair;

Обратите внимание, что для такого разбора регулярное выражение может быть немного излишним (шаблон очень прост и очень понятен).

Кроме того, предполагается, что у вас есть цифры с обеих сторон, как в вашем примере. Он также не изменяет строки при возврате результата.

2 голосов
/ 03 апреля 2011

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

1 голос
/ 03 апреля 2011

Хотя я думаю, что оба других ответа точны, я предполагаю, что вы не знакомы с некоторыми функциями .NET 2.0 и .NET 3.5, которые они использовали. Давайте сделаем это по одному шагу за раз.

Итак, вам дано ArrayList, содержащее следующие данные:

{ "1:1", "0:0", "0:1", "2:1", "1:0", "2:0" }

Прежде всего, нет ничего плохого в использовании RegEx; возможно незначительное снижение производительности. Если строки действительно так просты, вы можете просто использовать Split:

string[] s = myArray[i].Split(new[] { ':' });
int val1 = int.Parse(s[0]);
int val2 = int.Parse(s[1]);

Однако, поскольку вы сказали, что используете .NET 4, вам на самом деле вообще не следует использовать ArrayList - обратите внимание, что для этого требуется, чтобы вы приводили значения к их соответствующему типу, например string mystring = myArray[i] as string.

Существует множество замечательных функций, которыми вы не пользуетесь, таких как универсальные (в .NET Framework начиная с 2.0). Давайте напишем функцию, которая получает ArrayList, но возвращает отсортированный обобщенный List<string> (список, содержащий только строки). Давайте посмотрим:

/// <summary>
/// This method takes in an ArrayList of unsorted numbers in the format: a:b
/// and returns a sorted List<string> with a descending, b ascending
/// <summary>
public List<string> SortMyValues(ArrayList unsorted)
{
    // Declare an empty, generic List of type 'TwoNumbers'
    List<MyTuple> values = new List<MyTuple>();
    foreach (object item in unsorted)
    {
        char[] splitChar = new char[] { ':' };
        string itemString = item as string;
        string[] s = itemString.Split(splitChar);
        values.Add(new MyTuple{
            FirstNumber = int.Parse(s[0]),
            SecondNumber = int.Parse(s[1])
        });
    }
    // Sort the values
    values.Sort();
    // Return a list of strings, in the format given
    List<string> sorted = new List<string>();
    foreach (MyTuple item in values)
    {
        sorted.Add(item.FirstNumber + ":" + item.SecondNumber);
    }
    return sorted;
}

public class MyTuple : IComparable {
    public int FirstNumber { get; set; }
    public int SecondNumber { get; set; }

    public int CompareTo(object obj)
    {
        if (obj is MyTuple)
        {
            MyTuple other = (MyTuple)obj;

            // First number descending
            if (FirstNumber != other.FirstNumber)
            return other.FirstNumber.CompareTo(FirstNumber);
            // Second number ascending
        return SecondNumber.CompareTo(other.SecondNumber);
        }
        throw new ArgumentException("object is not a MyTuple");
    }
}

Теперь приведенный выше код работает, но на самом деле действительно длинный. Обратите внимание, что вам нужно создать класс только для хранения этих двух значений, сделать так, чтобы этот класс реализовывал IComparable и т. Д., И т. Д. Довольно раздражает!

.NET 3.5 вышел с некоторыми замечательными функциями, включая анонимные типы и LINQ . Давайте изменим наш код, чтобы использовать обе эти функции.

/// <summary>
/// This method takes in an ArrayList of unsorted numbers in the format: a:b
/// and returns a sorted List<string> with a descending, b ascending
/// <summary>
public List<string> SortMyValues(ArrayList unsorted)
{
    // First, cast every single element of the given ArrayList to a string
    // The Cast<T> method will do this, and return an enumerable collection
    return unsorted.Cast<string>()
        // Now, let's take this string data and create our objects that will hold two numbers
        .Select(item => {
            // This is the body of an anonymous method with one parameter, which I called 'item'
            // This anonymous method will be executed for every element in the collection
            string[] s = item.Split(new[] { ':' });
            // Here we create a new anonymous type holding our numbers
            // No need to define a new dummy class!
            return new {
                FirstNumber = int.Parse(s[0]),
                SecondNumber = int.Parse(s[1])
            };
        })
        // Now that we've got our objects, let's sort them
        .OrderByDescending(x => x.FirstNumber)
        .ThenBy(x => x.SecondNumber)
        // Finally, now that we're sorted properly, let's format our string list output
        .Select(x => x.FirstNumber + ":" + x.SecondNumber)
        .ToList();
}

Вся наша функция теперь занимает всего одну строку, и большая часть кода - это комментарии. Я рекомендую вам ознакомиться с некоторыми из этих функций и начать пользоваться ими; это сделает ваш код намного проще для чтения и записи; -)

Надеюсь, это помогло!

Редактировать: В ответ на ваш комментарий:

Что нужно сделать, чтобы они были в следующем порядке: 2:0 1:0 0:0 2:1 1:1 0:1

Похоже, вы сортируете по второму номеру по возрастанию, а затем по первому номеру по убыванию.

Просто измените код выше, чтобы использовать:

.OrderBy(x => x.SecondNumber)
.ThenByDescending(x => x.FirstNumber)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...