What's New in .NET 9 - LINQ Updates

November 26, 2024#Software Development
Article
Author image.

Sarah Dutkiewicz, Senior Trainer

LINQ (Language Integrated Query) has always been a game-changer for .NET developers, streamlining data manipulation with elegance and efficiency. With .NET 9, LINQ is leveling up with exciting new methods like CountBy, AggregateBy, and Index. These additions promise to make your data queries as strategic as a well-played game of Settlers of Catan. In this post, we’ll explore how these enhancements can bring order to your data chaos, just like a winning strategy brings victory in your favorite board games.

Starting Data

For our demos, we’ll have a collection of games with their names, genres, and prices.

We have a Game type with a name, genre, and price:

class Game
{
    public string Name { get; set; }
    public string Genre { get; set; }
    public decimal Price { get; set; }    
}

This is our collection of games:

 var games = new List<Game>
        {
            new Game { Name = "Werewolf", Genre = "Party", Price = 9.99m },
            new Game { Name = "Splendor", Genre = "Strategy", Price = 34.99m },
            new Game { Name = "Azul", Genre = "Abstract", Price = 29.99m },
            new Game { Name = "Bang", Genre = "Party", Price = 19.99m },
            new Game { Name = "Bärenpark", Genre = "Tile Placement", Price = 39.99m },
            new Game { Name = "Forbidden Planet", Genre = "Co-op", Price = 24.99m },
            new Game { Name = "Catan", Genre = "Strategy", Price = 44.99m },
            new Game { Name = "Ticket to Ride", Genre = "Strategy", Price = 49.99m },
            new Game { Name = "Hive", Genre = "Abstract", Price = 24.99m },
            new Game { Name = "Spyfall", Genre = "Party", Price = 14.99m },
            new Game { Name = "Spirit Island", Genre = "Co-op", Price = 59.99m },
            new Game { Name = "Draftosaurus", Genre = "Family", Price = 19.99m },
            new Game { Name = "7 Wonders", Genre = "Strategy", Price = 39.99m }
        };

Let’s see the new LINQ methods from .NET 9 in action!

CountBy

When it comes to counting by attribute or category, CountBy can assist with that! Consider this example, where we’re counting the number of games by their genre. This code returns a collection of <string, int>.

// Use CountBy to count games by genre
var gamesByGenre = games
    .Select(game => game.Genre)
    .CountBy(genre => genre);

// Output the results
Console.WriteLine("Games by genre:");
foreach (var (genre, count) in gamesByGenre)
{
    Console.WriteLine($"{genre}: {count}");
}

In this code, we have our collection of games, use Select to get just the genre, and use CountBy to get those counts. The output is this:

Games by genre:
Party: 3
Strategy: 4
Abstract: 2
Tile Placement: 1
Co-op: 2
Family: 1

🤔 I think we might like our strategy games.

If you find yourself analyzing collections and wanting to get counts for particular groups, CountBy can assist with that.

AggregateBy

When it comes to calculating values over a collection, AggregateBy can assist with this.

Consider this example where we are getting the sum of the costs by genre and sort it by most expensive to least expensive. In this example, we are seeding at 0 to be explicit.

// Use AggregateBy to calculate average price per genre
var totalPriceByGenre = games
    .AggregateBy(
        keySelector: game => game.Genre,
        seed: 0m,
        (totalValue, currentGame) => totalValue + currentGame.Price  // Aggregation function
    )
    .OrderByDescending(genrePrices => genrePrices.Value);

// Output the results
Console.WriteLine("Total price by genre:");
foreach (var (genre, price) in totalPriceByGenre)
{
    Console.WriteLine($"{genre}: ${price:F2}");
}

The output for this code is:

Total price by genre:
Strategy: $169.96
Co-op: $84.98
Abstract: $54.98
Party: $44.97
Tile Placement: $39.99
Family: $19.99

So where are we spending the most money? 💸 Strategy games!

Index

With Index, we can now get the index collection for an IEnumerable. When calling Index, it returns a tuple of (int, TSource). Suppose we want to create a list of our games from most expensive to least expensive and then alphabetically within the price. Let’s display it as a numbered list. Keep in mind that we’re looked at weirdly for starting our lists at 0, so we’ll start our list numbering at 1.

We will use LINQ’s OrderByDescending and ThenBy to order our List<Game> to achieve our ordering goal. Then, we will chain an Index call to get the index for that ordered collection’s results.

The foreach’s individual item is strongly typed in this demo so that you can see that, in our case, the Index call will return a tuple of (int index, Game game).

This code can achieve that:

IEnumerable<(int Index, Game Item)> indexedMostExpensiveGames = games
    .OrderByDescending(game => game.Price)
    .ThenBy(game => game.Name)
    .Index();

// Output the results
Console.WriteLine("Games - Most to Least Expensive:");
// Explicitly typing the tuple returned in the Index()
foreach ((int index, Game game) orderedGameEntry in indexedMostExpensiveGames)
{
    Console.WriteLine($"{orderedGameEntry.index + 1}. {orderedGameEntry.game.Name} - ${orderedGameEntry.game.Price:F2}");
}

This is the output:

Games - Most to Least Expensive:
1. Spirit Island - $59.99
2. Ticket to Ride - $49.99
3. Catan - $44.99
4. 7 Wonders - $39.99
5. Bärenpark - $39.99
6. Splendor - $34.99
7. Azul - $29.99
8. Forbidden Planet - $24.99
9. Hive - $24.99
10. Bang - $19.99
11. Draftosaurus - $19.99
12. Spyfall - $14.99
13. Werewolf - $9.99

Keep in mind that the index provided by Index starts at 0.

Conclusion

.NET 9’s LINQ updates are like upgrading your game pieces from cardboard to beautifully crafted miniatures—they take something you already love and make it even better. With CountBy, AggregateBy, and Index, you can write queries that feel as smooth as sliding your token across a pristine game board. Ready to play? Grab your tokens (or, in this case, your IDE), and dive into the strategic world of LINQ enhancements!

References


Copyright © 2024 NimblePros - All Rights Reserved