C # - сортировка строк - PullRequest
0 голосов
/ 27 июля 2011

У меня есть RichTextBox, который выглядит примерно так:

TEXT  TEXT-1     227.905  174.994  180  1111
TEXT  DIFTEXT    227.905  203.244  180  9999
TEXT  DIFTEXT2   242.210  181.294  180  2222
TEXT  TEXT-2     236.135  198.644  90   ABC1111
TEXT  SOMETEXT   250.610  201.594  0    DDDD
TEXT  OTHERTEXT  269.665  179.894  180  4444
TEXT  OTHERTEXT  269.665  198.144  180  1111

И я бы хотел отсортировать его в особом порядке. Допустим, я хочу отсортировать его по последнему значению (столбец 6) в следующей последовательности:

1111, 2222, 4444, 9999, DDDD

И затем отсортировать во-вторых по 2-й столбец в алфавитном порядке.

Таким образом, обновленный файл будет выглядеть следующим образом ПРИМЕЧАНИЕ. Поскольку сортировка для "ABC1111" отсутствует, он соответствует 1111 :

TEXT  OTHERTEXT  269.665  179.894  180  1111
TEXT  TEXT-1     227.905  174.994  180  1111
TEXT  TEXT-2     236.135  198.644  90   ABC1111   #See note above
TEXT  DIFTEXT2   242.210  181.294  180  2222
TEXT  OTHERTEXT  269.665  198.144  180  4444
TEXT  DIFTEXT    227.905  203.244  180  9999
TEXT  SOMETEXT   250.610  201.594  0    DDDD

И как только он будет в этом формате, я хотел бы записать его обратно в RichTextBox.

  • Как я могу это сделать?

Ответы [ 5 ]

2 голосов
/ 27 июля 2011

Класс TextBox уже даст вам массив строк без какой-либо работы с вашей стороны. Array.Sort позволит вам передать свой собственный код, который сравнивает строки. Я не могу придумать элегантный способ реализации неудобных правил сортировки, но способ, которым я решил бы вашу проблему, выглядел бы примерно так, как показано ниже. Обратите внимание, что вам нужно извлечь массив строк во временную переменную, чтобы вы могли установить его обратно, иначе установщик не будет вызван и текстовое поле не обновится.

private static void SortRichTextBox(RichTextBox richTextBox)
{
    var lineArray = richTextBox.Lines;
    Array.Sort(lineArray, delegate(string a, string b)
    {
        // I omitted Important corner cases like malformed lines,
        // empty strings, and nulls.

        // Additional sort cases can be added to the array as needed.
        var sortOrder = new[] { "1111", "2222", "4444", "9999", "DDDD" };
        var aTokens = a.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
        var bTokens = b.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

        var aSignifier = Array.FindIndex(sortOrder, item => aTokens[5].Contains(item));
        var bSignifier = Array.FindIndex(sortOrder, item => bTokens[5].Contains(item));

        // This is where your first rule is being implemented, based on the data
        // from the last column.  The math is unimportant, what matters is the 
        // return being positive vs. negative vs. zero.
        if (aSignifier != bSignifier)
            return aSignifier - bSignifier;

        // This is where your second rule is being implemented, as a backup when
        // the result from the first rule indicates equality.  We're just falling
        // through to ordinary string comparison on the second column.
        return aTokens[1].CompareTo(bTokens[1]);
    });

    // We want to call the setter to get the textbox to update.
    richTextBox.Lines = lineArray;
}

Я проверил это, и похоже, что оно работает, по крайней мере с вашим одним набором данных.

1 голос
/ 27 июля 2011
static void Main(string[] args)
{
    string input =
        "TEXT  TEXT-1     227.905  174.994  180  1111\n" +
        "TEXT  DIFTEXT    227.905  203.244  180  9999\n" +
        "TEXT  DIFTEXT2   242.210  181.294  180  2222\n" +
        "TEXT  TEXT-2     236.135  198.644  90   ABC1111\n" +
        "TEXT  SOMETEXT   250.610  201.594  0    DDDD\n" +
        "TEXT  OTHERTEXT  269.665  179.894  180  4444\n" +
        "TEXT  OTHERTEXT  269.665  198.144  180  1111";

    string[] lines = input.Split('\n');
    string[][] grid = new string[lines.Length][];
    for (int i = 0; i < lines.Length; i++)
    {
        grid[i] = lines[i].Split((char[])null, StringSplitOptions.RemoveEmptyEntries); // split on whitespace
    }

    IEnumerable<string[]> results = grid
        .OrderBy(gridRow => TransformColumn6(gridRow[5]))
        .ThenBy(gridRow => gridRow[1]);

    foreach (string[] gridRow in results)
    {
        Debug.WriteLine(string.Join(" ", gridRow));
    }
}

private static string TransformColumn6(string input)
{
    if (char.IsDigit(input[0]))
    {
        // string is a bunch of numbers, use as-is.
        return input;
    }

    int digitIndex = input.IndexOfAny(new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' });
    if (digitIndex == -1)
    {
        // string has no numbers, use as-is, will be sorted in alphabetical order after all the numbers.
        return input;
    }

    // string has a number, remove the stuff at the beginning.
    return input.Substring(digitIndex);
}

Результаты (форматирование столбца добавлено вручную):

TEXT OTHERTEXT 269.665 198.144 180 1111 
TEXT TEXT-1    227.905 174.994 180 1111 
TEXT TEXT-2    236.135 198.644 90  ABC1111 
TEXT DIFTEXT2  242.210 181.294 180 2222 
TEXT OTHERTEXT 269.665 179.894 180 4444 
TEXT DIFTEXT   227.905 203.244 180 9999 
TEXT SOMETEXT  250.610 201.594 0   DDDD 

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

0 голосов
/ 27 июля 2011

Принимая во внимание неясности, выделенные в моем комментарии. Вы можете разобрать строку в массив объектов (String.Split или String.Substring могут вам помочь, в зависимости от структуры ваших данных).

Затем используйте Array.Sort (сначала по свойству, представляющему столбец 2, затем по столбцу 6), чтобы отсортировать массив, как в примере здесь , который сортирует массив пользовательского типа.

Создайте .ToString метод для вашего класса, чтобы преобразовать каждый объект обратно в правильный формат.

0 голосов
/ 27 июля 2011

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

http://msdn.microsoft.com/en-us/library/bb383982.aspx

Предполагая, что вы можете получить их в объекты, вы можете использовать изпо порядку выберите

Чтобы обойти проблему abc1111, я бы создал отдельное свойство, по которому вы сортируете, которое содержит только 1111.

Кроме того, не забудьте принять ответы.

0 голосов
/ 27 июля 2011

Я бы скопировал данные в DataTable и использовал его для сортировки по нескольким столбцам, а затем скопировал данные обратно.

http://msdn.microsoft.com/en-us/library/system.data.dataview.sort.aspx

...