Я хочу отсортировать этот список в .NET, мой пример кода приведен ниже

#.net #linq #sql-order-by

#.net #linq #sql-order-by

Вопрос:

 class Program
{


    static void Main(string[] args)
    {

        //Period 01 2008, Period 02 2008
        Series s1 = new Series { Text = "Period 01 2008", Value = "1"};
        Series s2 = new Series { Text = "Period 02 2008", Value = "2" };
        Series s3 = new Series { Text = "Period 03 2008", Value = "3" };

        Series s11 = new Series { Text = "Period 01 2009", Value = "1" };
        Series s21 = new Series { Text = "Period 02 2009", Value = "2" };
        Series s31 = new Series { Text = "Period 03 2009", Value = "3" };

        Series s12 = new Series { Text = "Period 01 2010", Value = "1" };
        Series s22 = new Series { Text = "Period 02 2010", Value = "2" };
        Series s32 = new Series { Text = "Period 03 2010", Value = "3" };

        List<Series> series = new List<Series> { s21, s31, s1, s12, s11, s2, s22, s3, s32 };


       // mySeries.ForEach(i => Console.WriteLine("Period {0} {1}",i.Period, i.Year));
        series.ForEach(i => Console.WriteLine(i.Text));

        Console.WriteLine("************************");

        series.OrderBy(i => i.Text);

        series.ForEach(i=> Console.WriteLine(i.Text));

    }

}


public class Series
{
    public string Text { get; set; }
    public string Value {get;set;}
}
 

По сути, я хочу, чтобы мой список был упорядочен по Text свойству Series класса. У меня есть обходной путь путем разделения текста, но я ищу любой другой способ — IComparer возможно, используя?

Упорядоченный список должен быть примерно таким:

Период 01 2008, Период 02 2008, Период 03 2008, период 01 2009, период 02 2009…

Обновление: определение Series класса не может быть изменено.

Ответ №1:

Метод OrderBy расширения LINQ возвращает новую отсортированную последовательность, с которой вы ничего не делаете.
Это не изменяет исходный список.

Вместо этого вы можете вызвать List<T>.Sort , который является сортировкой на месте, которая изменяет List<T> экземпляр:

 series.Sort((a, b) => a.Text.CompareTo(b.Text));
 

Комментарии:

1. да, я понимаю, что вы имеете в виду, переведя эту строку в эту серию = series . OrderBy(i=> i.Text). ToList(); Я получаю вывод следующим образом Период 02 2009 Период 03 2009 Период 01 2008 Период 01 2010 Период 01 2009 Период 02 2008 Период 02 2010 Период 03 2008 Период 2008 Период 03 2010 ************************ Период 01 2008 Период 01 2009 Период 01 2010 Период 02 2008 Период 02 2009 Период 02 2010 Период 03 2008 Период 03 2009 Период 03 2010 Нажмите любую клавишу, чтобы продолжить . , , по я ищу что-то вроде этого Период 01 2008 Период 02 2008 Период 03 2008 2008

2. Вам нужно написать другой компаратор.

Ответ №2:

Добавьте следующий компаратор

 public class SeriesTextComparer : IComparer<string>
{
    public int Compare(string x, string y)
    {
        string[] xparts = x.Split(' ');
        string[] yparts = y.Split(' ');

        if (xparts[2] == yparts[2])
        {
            if (Convert.ToInt32(xparts[1]) > Convert.ToInt32(yparts[1]))
            {
                return 1;
            }
            else if(Convert.ToInt32(xparts[1]) < Convert.ToInt32(yparts[1]))
            { 
                return -1;
            }
            else
            {
                return 0;
            }
        }
        else
        { 
        if (Convert.ToInt32(xparts[2]) > Convert.ToInt32(yparts[2]))
            {
                return 1;
            }
            else if(Convert.ToInt32(xparts[2]) < Convert.ToInt32(yparts[2]))
            { 
                return -1;
            }
            else
            {
                return 0;
            }
        }
    }
}
 

И измените последние две строки в вашем примере, как показано ниже

 List<Series> sortedSeries =  series.OrderBy(i => i.Text, new SeriesTextComparer()).ToList();
sortedSeries.ForEach(i => Console.WriteLine(i.Text));
 

Комментарии:

1. Я предполагаю, что у вас всегда будут номера месяцев и лет в позициях 2 и 3. Следовательно, в моем коде нет проверок ошибок. Вы можете добавить проверки на ошибки, если хотите

2. Большое спасибо, это то, чего я ожидал. да, годы и период всегда будут в этом положении

3. @pavan-josyula если это решит вашу проблему, возможно, вы можете принять ответ

Ответ №3:

Обновите вторую последнюю строку в методе main до:

 series = series.OrderBy(i => i.Text).ToList(); 

Счастливого кодирования

Комментарии:

1. Вот как я получаю ************************ Период 01 2008 Период 01 2009 Период 01 2010 Период 02 2008 Период 02 2009 Период 02 2010 Период 03 2008 Период 03 2009 Период 03 2010 Нажмите любую клавишу, чтобыпродолжить . , , но я ищу период 01 2008, период 02 2008, период 03 2008, период 01 2009, период 02 2009 и так далее

2. Я понимаю, что вы имеете в виду, вам нужно изменить последнюю строку, например: series. ForEach(i=> Консоль. WriteLine(i.Text) «,»); не так ли

Ответ №4:

Я бы добавил DateTime свойство

 Series s1 = new Series { 
    Text = "Period 01 2008", 
    Value = "1", 
    PeriodStart = new DateTime(2008, 01, 01) 
};
 

и порядок по нему:

 series.OrderBy(i => i.PeriodStart).ForEach(i => Console.WriteLine(i.Text));
 

таким образом, вы не получаете все январские номера вместе.

Кроме того, на вашу сортировку не повлияют какие-либо изменения в Text свойстве, которые предназначены для отображения.

Комментарии:

1. -1 ForEach включен List<T> , поэтому он не компилируется. Изменения в тексте, вероятно, должны повлиять на сортировку, и, хотя это не указано, OP не может изменить определение Series класса. ToList на OrderBy исправит ваш пример.

Ответ №5:

Хотя я бы не стал этого делать сам, это работает:

 var sorted = series.OrderBy(s => s.Text.Split(' ')[2].Trim()).ThenBy(s => s.Text.Split(' ')[1].Trim());
 

Это демонстрирует тип LINQ, необходимый для сортировки. Я этого здесь не делал, но вам нужно будет более осторожно относиться к нулевым / отсутствующим строковым частям.

В качестве альтернативы

Немного другой способ решения проблемы — обернуть Series класс и предоставить больше полезных свойств (отказ от ответственности, требуется лучший код синтаксического анализа!):

 class BetterSeries
{
    public int Quarter {get;set;}
    public int Year {get;set;}
    public Series InnerSeries {get;private set;}

    public BetterSeries(Series s)
    {
        string[] parts = s.Text.Split(' ');
        Quarter = int.Parse(parts[1].Trim());
        Year = int.Parse(parts[2].Trim());
        InnerSeries = s;
    }

    public override string ToString()
    {
        return string.Format("Period {0} {1}", Quarter, Year);
    }
}
 

Это позволит вам отсортировать немного проще:

 var sorted = series.OrderBy(s => s.Year).ThenBy(s => s.Quarter);
 

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

Комментарии:

1. но проблема в том, что я не могу изменить определение класса. Текст всегда приходит в таком формате «Период 01 ГГГГ». Мне нужно отсортировать его по номеру периода, а затем по году

2. -1 — Я полагаю, у вас возникнут проблемы с сохранением порядка: msdn.microsoft.com/en-us/library/bb534966.aspx

3. @JakubKonecki Где в этой ссылке упоминается сохранение? Я действительно попробовал этот код в консольном приложении, и он работает нормально.

4. @AdamHouldsworth не могли бы вы поделиться выводом один раз

5. @PavanJosyula Результат совпадает с тем, что вы ожидаете, но вы только что прокомментировали, что не можете изменить определение ряда. Единственный способ, которым вы сможете правильно отсортировать его, — это либо алфавитная сортировка, либо вы разбиваете строку на части.