C#でリストを生成したい。Python のリスト内包表記がありません。リスト内包表記やジェネレーター式が Python で行うように、その場でコレクションを作成する C# の方法はありますか?
5 に答える
C# 3.0 (VS2008) を使用している場合、LINQ to Objects は非常によく似た処理を実行できます。
List<Foo> fooList = new List<Foo>();
IEnumerable<Foo> extract = from foo in fooList where foo.Bar > 10 select Foo.Name.ToUpper();
Mattはクエリ式について言及しています。ちなみに、これらはLINQ to Objectsだけでなく、一般的にLINQで使用できます。(たとえば、LINQ to SQLデータコンテキストに適用された同じクエリは、データベースでフィルターと射影を実行します。)
C#3のクエリ式は、通常のC#コードの記述よりも単純に構文上の糖衣ですが、クエリ式は通常、拡張メソッドを呼び出すことになります。(必要はなく、コンパイラーは気にしませんが、通常は気にします。)C#クエリ式では使用できないが、メソッド呼び出しでサポートされているコレクションを使用して実行できるさまざまなことがあります。両方の種類の構文に注意する価値があります。たとえば、Mattのクエリ式は次のとおりです。
List<Foo> fooList = new List<Foo>();
IEnumerable<string> extract = from foo in fooList where foo.Bar > 10 select foo.Name.ToUpper();
次のように「前処理」されます。
List<Foo> fooList = new List<Foo>();
IEnumerable<string> extract = fooList.Where(foo => foo.Bar > 10)
.Select(foo => foo.Name.ToUpper());
元のコレクションの値のインデックスに基づいて(たとえば)フィルタリングする場合は、クエリ式では使用できないWhereの適切なオーバーロードを使用できます。
List<Foo> fooList = new List<Foo>();
IEnumerable<string> extract = fooList.Where((foo, index) => foo.Bar > 10 + index)
.Select(foo => foo.Name.ToUpper());
または、基準に一致する最長の名前の長さを見つけることができます。
List<Foo> fooList = new List<Foo>();
int longestName = fooList.Where((foo, index) => foo.Bar > 10 + index)
.Select(foo => foo.Name)
.Max();
(プロジェクションとmaxを別々の方法で実行する必要はありません。プロジェクションを取得するオーバーMax
ロードもあります。)
私のポイントは、拡張メソッドを使用すると、高度なクエリを非常に簡単に構築できるということです。
Pythonジェネレーターについても言及します-C#にはイテレーターブロックの形式でこれがあります。実際、これらはLINQのような演算子を実装するときに非常に便利です。(LINQ to Objectsのほとんどは拡張メソッドに基づいているため、クエリ式の構文を自分で変更することはできませんが、LINQに「ネイティブ」に見える独自の演算子を追加できます。)
List<T>.ConvertAll
既存のリストのすべての項目に対して同じ操作を実行し、新しいコレクションを返すことにより、リスト内包表記と同じように動作します。これは、特にまだ .NET 2.0 を使用している場合に、Linq を使用する代わりの方法です。
Python での単純なリスト内包表記の例:
>>> foo = [1, 2, 3]
>>> bar = [x * 2 for x in foo]
>>> bar
[2, 4, 6]
C# 3.0 では、必要なマッピング関数のタイプを指定するラムダ関数を渡すことができます。
public static void Main()
{
var foo = new List<int>{ 1, 2, 3};
var bar = foo.ConvertAll(x => x * 2); // list comprehension
foreach (var x in bar)
{
Console.WriteLine(x); // should print 2 4 6
}
}
C# 2.0 では、デリゲートで匿名メソッドを使用しConverter
て同等の処理を実行できます。
public static void Main()
{
List<int> foo = new List<int>(new int[]{ 1, 2, 3});
List<int> bar = foo.ConvertAll(new Converter<int, int>(delegate(int x){ return x * 2; })); // list comprehension
foreach (int x in bar)
{
Console.WriteLine(x); // should print 2 4 6
}
}
(注: 同じことを配列で行うことができます。Array.ConvertAll
これがあります:
new List<FooBar> { new Foo(), new Bar() }
これは、同等の python よりも少し長いだけです。
[Foo(), Bar()]
そして、これがあります:
public IEnumerable<FooBar> myFooBarGenerator() {
yield return new Foo();
yield return new Bar();
}
これは、次の python に相当します。
def myFooBarGenerator():
yield Foo()
yield Bar()