paul
paul

Reputation: 50

C# LINQ calculated Group By

To take it down to brass tacks, I have a List containing 100 various records. A Car has a Year, Make and Model.

I need to be able to :

  1. order this according to Year, but I need to:

  2. have all Cars that are Ford Explorers appear as a "group" at the end of my List (also ordered according to Year)

I'm not sure if I'll have to create 2 separate List and then merge them... seems like there should be a better way to do this than having to create multiple objects.

Your help is appreciated and welcomed!

Many Thanks, paul

Example:



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


Upvotes: 1

Views: 946

Answers (3)

Bill Barry
Bill Barry

Reputation: 3523

cars.OrderBy(c => 
        (c.Make == "Ford" && c.Model == "Explorer")
        ? c.Year + 10000
        : c.Year)
    .ToList()

thinking about my comment below, if it were LINQ to sql, I would probably write it with a union:

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

Upvotes: 0

Jon Skeet
Jon Skeet

Reputation: 1500675

This should do it:

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

(Obviously adjust the test for Ford Explorer-ness.)

Basically think of Ford Explorer-ness as a Boolean property, where false is ordered before true. You can express this as a query expression too, of course:

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

(I tend to prefer dot notation in this case.)

Upvotes: 2

jrista
jrista

Reputation: 32960

If you truly only want the Ford Explorers to be grouped, you can do the following:

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

What the above query does is create an inline value , isFordExplorer, and assigns it a boolean value using the let keyword indicating whether the car is a Ford Explorer. That value can then be sorted by, along with the Year. The following is a working program that should demonstrate the concept:

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

Upvotes: 3

Related Questions