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

Мне нужно уметь:

  1. Закажите это в соответствии с Годом, но мне нужно:

  2. есть все автомобили Ford Исследователи появляются в виде "группы" на конец моего списка (также заказанный по Году)

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

Ваша помощь приветствуется и приветствуется!

Большое спасибо, Пол

Примере:



2001 Hummer H1
2002 Ford Focus
2008 BMW 325i
2008 Ford Escape
2009 BMW 328i
2009 Mitsubishi Galant
Ford Explorer 2003 года
Ford Explorer 2004 года
Ford Explorer 2008 года
Ford Explorer 2009 года


1
paul 24 Июн 2010 в 20:30
1
Не могли бы вы привести пример вашего списка? Вы хотите сгруппировать только Ford Explorer (который представляет собой комбинацию марки и модели) или хотите сгруппировать все марки и все модели и отсортировать каждую группу по годам? Кроме того, что вы подразумеваете под "группой" ... вы просто хотите упорядочить по make, model, year или вам действительно нужны группы make, model, упорядоченные по year?
 – 
jrista
24 Июн 2010 в 20:33
Меня не волнует, помечены ли они группой, просто все Ford Explorers появляются в конце в предпочтительном порядке. Представьте, что исходный список перемешан. Итак, вот пример того, как это должно выглядеть, когда все будет готово. / * 2001 Hummer H1 2002 Ford Focus 2008 BMW 325i 2008 Ford Escape 2009 BMW 328i 2009 Mitsubishi Galant 2003 Ford Explorer 2004 Ford Explorer 2008 Ford Explorer 2009 Ford Explorer * / Galant завершит первую группу
 – 
paul
24 Июн 2010 в 20:39
Не знаю, как делать разрывы строк в этих комментариях ... извините.
 – 
paul
24 Июн 2010 в 20:44
Я добавил ваш пример в ваш OP. :)
 – 
jrista
24 Июн 2010 в 20:52

3 ответа

Лучший ответ

Если вы действительно хотите сгруппировать только Ford Explorers, вы можете сделать следующее:

var groupedByFordExplorer = from c in cars
                    let isFordExplorer = c.Make == "Ford" && c.Model == "Explorer"
                    orderby isFordExplorer, c.Year
                    select c;

Вышеупомянутый запрос создает встроенное значение isFordExplorer и присваивает ему логическое значение с помощью ключевого слова let, указывающего, является ли автомобиль Ford Explorer. Затем это значение можно отсортировать вместе с Годом. Ниже представлена ​​рабочая программа, которая должна продемонстрировать концепцию:

class Program
{
    static void Main(string[] args)
    {
        var cars = new List<Car>
        {
            new Car { Year = 2009, Make = "Ford", Model = "Explorer" },
            new Car { Year = 2001, Make = "Hummer", Model = "H1" },             
            new Car { Year = 2002, Make = "Ford", Model = "Focus" },
            new Car { Year = 2008, Make = "BMW", Model = "325i" },
            new Car { Year = 2008, Make = "Ford", Model = "Explorer" },             
            new Car { Year = 2008, Make = "Ford", Model = "Escape" },               
            new Car { Year = 2009, Make = "Mitsubishi", Model = "Galant" },
            new Car { Year = 2004, Make = "Ford", Model = "Explorer" },
            new Car { Year = 2009, Make = "BMW", Model = "329i" },
            new Car { Year = 2003, Make = "Ford", Model = "Explorer" }              
        };

        var groupedByFordExplorer = from c in cars
                                    let isFordExplorer = c.Make == "Ford" && c.Model == "Explorer"
                                    orderby isFordExplorer, c.Year
                                    select c;

        foreach (var car in groupedByFordExplorer)
        {
            Console.WriteLine("{0} {1} {2}", car.Year, car.Make, car.Model);
        }

        Console.ReadLine();
    }
}

class Car
{
    public int Year { get; set; }
    public string Make { get; set; }
    public string Model { get; set; }
}
3
jrista 24 Июн 2010 в 20:52
Обратите внимание, что, хотя вы можете сохранить эту «встроенную» переменную для удобства чтения, на самом деле в этом нет необходимости. Лично я не уверен, что это даже улучшает читаемость, но красота в глазах смотрящего. Я до сих пор считаю, что точечная нотация самая простая :)
 – 
Jon Skeet
24 Июн 2010 в 20:56
Это сработало как шарм. Я часто забываю о команде let .... идеально подходящей для перебора вычисленных данных. Большое спасибо!
 – 
paul
24 Июн 2010 в 21:17
Скит: Хотя я уважаю ваше мнение, я думаю, что силу термина let не следует недооценивать. Мне лично нравится точечная нотация для большинства простых вещей, однако синтаксис запросов LINQ предлагает много возможностей и контроля с помощью let, которых просто не может достичь точечная нотация. Думаю, этот простой пример - хорошая демонстрация этого полезного инструмента. Я думаю, также следует отметить, что это инструмент для решения проблем ... насколько красив код, не так много для меня значит, как то, насколько он способен является. Однако я по-прежнему предпочитаю удобочитаемость синтаксиса запроса синтаксису с точками.
 – 
jrista
24 Июн 2010 в 21:45
Как я уже сказал, красота (которую я считаю почти синонимом удобочитаемости) в глазах смотрящего. В этом случае в выражении запроса есть много лишнего мусора, тогда как точечная нотация выражает только то, что интересно. Например, в выражении запроса требуется «выбор», который не выражает того, что вас действительно интересует, если вы рассматриваете его как последовательность автомобилей с самого начала. Я думаю, что let полезно, когда вы используете одно и то же выражение более одного раза, или когда это сложно, а присвоение концепции имени помогает для ясности - но в этом случае я бы не стал его использовать.
 – 
Jon Skeet
24 Июн 2010 в 22:48
Скит: Я не согласен. Я думаю, что использование .OrderBy в вашем примере на самом деле немного сбивает с толку, поскольку не очевидно, что вы сортируете по логическому, а не по свойству объекта автомобиля. Использование let, как я, очень ясно показывает, что вы выполняете сортировку по логическому значению. Я согласен с тем, что ключевое слово select довольно "бесполезно", но оно никоим образом не снижает ясности утверждения. Это может быть не «красиво», но читабельно, понятно и ясно в смысле цели.
 – 
jrista
25 Июн 2010 в 03:05

Это должно сделать это:

var query = list.OrderBy(car => car.Make == "Ford" && car.Model == "Explorer")
                .ThenBy(car => car.Year);

(Очевидно, отрегулируйте тест на соответствие Ford Explorer.)

В основном думайте о Ford Explorer-ness как о логическом свойстве, где ложь предшествует истине. Конечно, вы также можете выразить это как выражение запроса:

var query = from car in list
            orderby car.Make == "Ford" && car.Model == "Explorer", car.Year
            select car;

(В этом случае я предпочитаю точечную нотацию.)

2
Jon Skeet 24 Июн 2010 в 20:53
Автомобиль не имеет Типа. только марка и модель ... но мы близки
 – 
paul
24 Июн 2010 в 20:46
Этот новый сценарий также будет работать. Однако использование синтаксиса let лучше всего работает в моем реальном приложении. Спасибо за помощь и полезное обсуждение!
 – 
paul
25 Июн 2010 в 21:41
cars.OrderBy(c => 
        (c.Make == "Ford" && c.Model == "Explorer")
        ? c.Year + 10000
        : c.Year)
    .ToList()

Думая о моем комментарии ниже, если бы это был LINQ to sql, я бы, вероятно, написал его с объединением:

cars.Where(c => c.Make != "Ford" || c.Model != "Explorer")
    .OrderBy(c => c.Year)
    .Union(cars.Where(c => c.Make == "Ford" && c.Model == "Explorer")
               .OrderBy(c => c.Year))
0
Bill Barry 24 Июн 2010 в 20:57
К счастью, LINQ предоставляет более удобные способы упорядочивания по составному ключу :)
 – 
Jon Skeet
24 Июн 2010 в 20:41
Да, но это приводит к двухпроходной сортировке, тогда как это выполняется только один раз. Если бы это был LINQ to sql или какая-либо другая форма, в которой выражение оценивается перед выполнением, то более красивая форма была бы лучше (гораздо более вероятно, что она будет преобразована при выполнении); прямо LINQ с POCO, это решение будет сортировать за один проход и поэтому должно улучшаться по мере роста набора данных.
 – 
Bill Barry
24 Июн 2010 в 20:48
Я не верю, что для этого действительно требуется двухпроходная сортировка. Насколько мне известно, сортировка просто выполняется с использованием сравнения, в котором учитываются оба бита. Конечно, так работает моя демонстрационная реализация LINQ to Objects :) Даже если бы этот код был несколько быстрее, я бы определенно придерживался более читаемого кода, пока не показал, что у него есть проблемы с производительностью. .
 – 
Jon Skeet
24 Июн 2010 в 21:16