Zenn
📝

C#でリスト内包表記(風)

2025/02/24に公開

こうする

例:整数列 collection から偶数列をもとめる
List<int> list = [.. from item in collection where item % 2 == 0 select item];

数列をゼロから作るパターン

要拡張メソッド To()
List<int> list2 = [.. from x in (0..9).To() where x % 2 == 0 select x];
拡張メソッド To() の実装
//拡張メソッド
public static class RangeExtensions
{
    public static IEnumerable<int> To(this Range range)
    {
        int start = range.Start.Value;
        int end = range.End.Value;
        return Enumerable.Range(start, end - start);
    }
}
拡張メソッドつかわない(ちょっとリスト内包表記ぽくない)
List<int> list3 = [.. from x in Enumerable.Range(0,10) where x % 2 == 0 select x];

他の例

ネスト列(タプルのリスト)をつくる

List<(int, int)> pairs = [ .. from x in (0..3).To() from y in (0..3).To() select (x, y)];
//(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)

フィルタしてソート

5以上をフィルタして降順ソート
List<int> list4 = [.. from item in collection where item > 5 orderby item descending select item];

カラクリ

コレクション式(C#12.0) + LINQクエリ式(C#3.0)

  • レガシーなLINQクエリ式と最近のコレクション式の組み合わせ

  • 「誰も使ってない」クエリ式の意外な使いどころ

  • LINQは単なる高階関数じゃないぞアピール

  • LINQ登場時にもリスト内包表記っぽいと言われてたけどコレクション式でもっとそれっぽく

  • (0..9).To()の例はRangeなのでC#8.0で登場。

https://learn.microsoft.com/ja-jp/dotnet/csharp/linq/get-started/introduction-to-linq-queries

https://learn.microsoft.com/ja-jp/dotnet/csharp/language-reference/operators/collection-expressions

これはできない(C#13.0時点)

varで宣言

There is no target type for the collection expression.
var listF = [.. from x in (0..9).To() where x % 2 == 0 select x];

左辺の型指定がvarにできるともっとリスト内包表記っぽい。
現時点だとこれはまだ無理。

https://github.com/dotnet/csharplang/discussions/8660

辞書内包表記っぽいヤツ

✘これはできない
List<string> names = ["Alice", "Bob", "Charlie"];
Dictionary<string, int> dict = [.. from s in names select (s, s.Length)];

現時点だとこれはできない。
ディクショナリ式」が入ればそれっぽいのができるかも。

.NET Fiddle

https://dotnetfiddle.net/IHfmyJ

Discussion

ログインするとコメントできます