概要
NET Framework 3.5でLINQが実装され、NET Framework 4.0でZipメソッドが追加されました。
それ以降、なかなかメソッドは増えていなかったのですが、最近になっていくつかLINQ to Objectsにメソッドが追加されています。
この投稿ではそれらを紹介します。
-
Prepend
とAppend
-
TakeLast
とSkipLast
ToHashSet
PrependとAppend
- Prepend : 先頭に要素を追加した新しい
IEnumerable<T>
をつくる - Append : 末尾に要素を追加した新しい
IEnumerable<T>
をつくる
Prepend
とAppend
は、元のIEnumerable<T>
を実装したオブジェクトの中身を変更しません。
サンプルコード
Prepend
。元のIEnumerable<T>
を実装したオブジェクトに副作用を与えないことに注目。
// Creating a list of numbers
List<int> numbers = new List<int> { 1, 2, 3, 4 };
// Trying to prepend any value of the same type
numbers.Prepend(0);
// It doesn't work because the original list has not been changed
Console.WriteLine(string.Join(", ", numbers));
// It works now because we are using a changed copy of the original list
Console.WriteLine(string.Join(", ", numbers.Prepend(0)));
// If you prefer, you can create a new list explicitly
List<int> newNumbers = numbers.Prepend(0).ToList();
// And then write to the console output
Console.WriteLine(string.Join(", ", newNumbers));
// This code produces the following output:
//
// 1, 2, 3, 4
// 0, 1, 2, 3, 4
// 0, 1, 2, 3, 4
Append
。こっちも、元のIEnumerable<T>
を実装したオブジェクトに副作用を与えないことに注目。
// Creating a list of numbers
List<int> numbers = new List<int> { 1, 2, 3, 4 };
// Trying to append any value of the same type
numbers.Append(5);
// It doesn't work because the original list has not been changed
Console.WriteLine(string.Join(", ", numbers));
// It works now because we are using a changed copy of the original list
Console.WriteLine(string.Join(", ", numbers.Append(5)));
// If you prefer, you can create a new list explicitly
List<int> newNumbers = numbers.Append(5).ToList();
// And then write to the console output
Console.WriteLine(string.Join(", ", newNumbers));
// This code produces the following output:
//
// 1, 2, 3, 4
// 1, 2, 3, 4, 5
// 1, 2, 3, 4, 5
シグニチャ
public static IEnumerable<TSource> Append<TSource>(this IEnumerable<TSource> source, TSource element);
public static IEnumerable<TSource> Prepend<TSource>(this IEnumerable<TSource> source, TSource element);
利用できる環境
- .NET Core 1.0~
- .NET Framewprk 4.7.1~
ちなみにこのメソッドは、.NET Standard 1.6に入ったので、上記環境以外にも.NET Standardを準拠する環境ですでに入っています。
TODO 確認と動作検証
.NET Framework 4.6.1は、.NET Standard 1.6に準拠しています。
サポートファイルを使えば、Append・Prependは使える可能性あり。
一方、公式ドキュメントには記載はありません。
要動作検証
参考 .NET Framework 4.7.1 provides built-in support for .NET Standard 2.0
関連
- Enumerable.Prepend Method(公式APIドキュメント)
- Enumerable.Append Method(公式APIドキュメント)
- .NET Standard 1.6 vs. 1.5
- .NET Framework 4.7.1 provides built-in support for .NET Standard 2.0 (dotnet/standardのissue)
ToHashSet
名前から想像できる通り、ToList
やToDictionary
のHashSet
版。IEnumerable<T>
からHashSet<T>
を作成するメソッドです。
重複要素を取り除いて、HashSet<T>
を生成したい時に使うメソッドです。
重複を取り除くという観点では似たようなメソッドに、Distinctがあります。
-
ToHashSet
はToList
やToDictionary
と同様に、メソッド呼び出しと同時に全ての要素が列挙されてコレクションが生成される -
Distinct
は、Select
やWhere
と同様に、メソッド呼び出した時に要素の列挙はされない。Distinct
の返り値のIEnumerable<T>
が列挙された時に、重複排除の内部処理が走る。
シグニチャ
public static HashSet<TSource> ToHashSet<TSource>(this IEnumerable<TSource> source);
public static HashSet<TSource> ToHashSet<TSource>(this IEnumerable<TSource> source, IEqualityComparer<TSource> comparer);
利用できる環境
- .NET Core 2.0~
- .NET Framewprk 4.7.2~
ちなみにこのメソッドは、.NET Standard 2.1に入ったので、上記環境以外にも.NET Standardを準拠する環境で将来的に入る見込みですね。
関連
- Enumerable.ToHashSet Method(公式APIドキュメント)
- Announcing the .NET Framework 4.7.2の「BCL – Additional Collection APIs」
- Announcing .NET Standard 2.1
- .NET Standard 2.1 vs. 2.0
TakeLastとSkipLast
まずは、TakeLast
。
Take
の末尾からやる版。指定個数countを渡し、元のIEnumerable<T>
から末尾から指定個数個だけ要素をピックアップしたIEnumerable<T>
を生成するメソッドです。
Returns a specified number of contiguous elements from the end of a sequence.
Take
と同様に
- 引数のcountが0以下の時は、例外が発生したりせず、空の
IEnumerable<T>
- 引数のcountが
IEnumerable<T>
の長さより大きい場合は、例外が発生したりせず、全ての要素がピックされたIEnumerable<T>
次は、SkipLast
.
Skip
の末尾からやる版。指定個数countを渡し、元のIEnumerable<T>
から、末尾から指定個数個だけ取り除いたIEnumerable<T>
を生成するメソッドです。
Omits a specified number of elements from the end of a sequence and returns the remaining elements.
Skip
と同様に
- 引数のcountが0以下の時、例外が発生したりせず、何も要素が取り除かれていない
IEnumerable<T>
- 引数のcountが
IEnumerable<T>
の長さより大きい場合は、例外が発生したりせず、空のIEnumerable<T>
シグニチャ
public static IEnumerable<TSource> SkipLast<TSource>(this IEnumerable<TSource> source, int count);
public static IEnumerable<TSource> TakeLast<TSource>(this IEnumerable<TSource> source, int count);
利用できる環境
- .NET Core 2.0~
ちなみにこのメソッドは、.NET Standard 2.1に入ったので、上記環境以外にも.NET Standardに準拠した環境で将来的に入る見込みですね。
そのうち、.NET Frameworkでも使えるようになると思います。。
あと、Ix.NETにも同様なメソッドが存在します。.NET Core以外で今すぐ使いたいのであれば、Ix.NETを導入するのもありかもしれません。
関連
- Enumerable.TakeLast Method(公式APIドキュメント)
- Enumerable.SkipLast Method(公式APIドキュメント)
- Announcing the .NET Framework 4.7.2の「BCL – Additional Collection APIs」
- Announcing .NET Standard 2.1
- dotnet/reactive(Ix.NETを含むGitHubリポジトリ)
- .NET Standard 2.1 vs. 2.0
Zip
今までは、
public static IEnumerable<TResult> Zip<TFirst,TSecond,TResult> (this IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func<TFirst,TSecond,TResult> resultSelector);
- シーケンス(
IEnumerable<TFirst>
) - シーケンス(
IEnumerable<TFirst>
) - 合成するためのデリゲート(
Func<TFirst, TSecond, TResult>
)
を引数にとって、
- シーケンス(
IEnumerable<TResult>
)
を返すメソッドしかありませんでした。
これに新しいオーバーロードが追加されました。
新しいオーバーロードは、「合成するデリゲート」が必要ないものです。
- シーケンス(
IEnumerable<TFirst>
) - シーケンス(
IEnumerable<TFirst>
)
を引数に、
- シーケンス(
IEnumerable<ValueTuple<TFirst, TSecond>
)
を返すものです。
嬉しい!
Zipする時って、「とりあえずまとめて後続の処理につなげる」ことも多いので、そのシーンでわざわざ「合成するためのデリゲート(Func<TFirst, TSecond, TResult>
)」を用意する必要がないのがうれしい!
今までは↓こんな感じで、「合成するためのデリゲート(Func<TFirst, TSecond, TResult>
)」が必要。匿名型とかと組み合わせることも多い
foreach(var element in firstSequence.Zip(secondSequence, (first, second) => new {first, second})){
var first = element.first;
var second = element.second;
Console.WriteLine(first + " " + second);
}
今までは↓こんな感じで、ZipしてValueTupeに。分解とのコンボも!短くてスッキリ!
foreach(var (first, second) in firstSequence.Zip(secondSequence)){
Console.WriteLine(first + " " + second);
}
シグニチャ
public static IEnumerable<ValueTuple<TFirst,TSecond>> Zip<TFirst,TSecond> (this IEnumerable<TFirst> first, IEnumerable<TSecond> second);
利用できる環境
- .NET Core 3.0
.NET Core 3.0は現在Previewの段階です。
Zipメソッドは、Preview5から使えるようになりました。
同様のメソッドが拙作のImportedLinqにもあるので、本番環境で今すぐ使いたい人はそちらを使ってみてください。
関連
Corefxの関連 Issue
Corefxの関連 PullRequest