Open15
C# 逆引きコレクション式

目次
内容 | 書き方 |
---|---|
コレクション同士の結合 | TCollection c = [..a, ..b]; |
コレクションのキャスト | T2 t2 = [..t1]; |
コレクションの初期化 | TCollection a = []; |
コレクションの空の判定 | collection is [] |
同じ値のコレクションを要素数指定して作る | TCollection c = [.. Enumerable.Repeat(val, num)] |
連番コレクションを作る | TCollection c = [.. Enumerable.Range(start, count)] |
コレクションを分割して前後入替 | c = [..c[index..], ..c[..index]] |
コレクションから指定indexの要素を削除 | a = [ .. a[..index], .. a[(index+1)..] ]; |
コレクションの先頭や末尾に要素を追加 |
a = [elem, ..a] / a = [..a, elem]
|
補足
「コレクション」はこのページではTCollection
で表現します
ここでいう「コレクション」は,
-
T[]
(配列) IEnumerable<T>
List<T>
-
Span<T>
とか。
Dictionary<K,V>
とかのディクショナリは「ディクショナリ式」という別のものが
C#14.0?以降に入る予定。
string
もコレクション式が使える場合がある。

コレクション同士の結合
コレクション式
//a,bはTCollection
TCollection c = [..a, ..b];
[..【結合するコレクションA】, ..【結合するコレクションB】]
でOK。
//3つでも4つでも
List<T> x = [..a, ..b, ..c];
//順番もお好きに
List<T> r = [..c, ..b, ..a];
古い書き方
Concat()だったりAppend()だったり、そもそも結合するメソッドが無かったり。
//T[]
T[] combinedArray = array1.Concat(array2).ToArray();
//IEnumerable<T>
IEnumerable<T> combinedCollection = collection1.Concat(collection2);
//List<T>
list1.AddRange(list2);
//ImmutableArray<T>
ImmutableArray<T> combinedArray = array1.Append(array2);
//Span<T>
//..CopyTo()とか使って色々めんどくさいので省略..

コレクションのキャスト
コレクション式
//t1は別の型TCollection1
TCollection2 t2 = [ ..t1 ];
暗黙の型変換できないものも同じ書き方でキャストできる。
int[] array = [];
//cast
IEnumerable<int> ienumerable = [..array];
IEnumerable<int> ie2 = array; //暗黙の型変換できる
List<int> list = [..array];
Span<int> span = [..array];
Span<int> span2 = array; //暗黙の型変換できる
古い書き方
int[] array = { 1, 2, 3 };
List<int> list = new List<int> { 1, 2, 3 };
//T[] から List<T>
List<int> list = new List<int>(array);
//T[] から Span<T>
Span<int> span = array.AsSpan();
//List<T> から T[]
int[] array = list.ToArray();
//List<T>からSpan<T>
Span<int> span = list.ToArray().AsSpan();

コレクションの初期化
コレクション式
TCollection a = [];
どんな場合も基本的に[]
。
最代入可能なら、[]
で空にすることもできる。
List<int> list = [1,2,3];
list = []; //空に
古い書き方
//配列は{}が使えた
int[] array1 = {};
//インターフェイスなんでnewとかできない
IEnumerable<int> ienum1 = Enumerable.Empty<int>();
//newする場合&型が明らかならnew()で省略できる
List<int> list1 = new();
Span<int> span1 = new();

コレクションの空の判定
コレクション式
//TCollection collection
collection is []
正確にはパターンマッチのリストパターン。コレクション式と同じ書き方になっている。
nullチェックも同時に行われる。
nullの場合の判定もしたい場合はこう。
collection is null or []
古い書き方
if (array != null && array.Length == 0 )
if (list != null && list.Count == 0)
if (span.Length == 0)
if (text != null && text.Length == 0)

同じ値のコレクションを要素数指定して作る
コレクション式
//valueは要素の共通の値
TCollection a = [.. Enumerable.Repeat(value,10)];
Enumerable.Repeat()
を[]
内でspreadするだけでどんな型のコレクションもいける。
古い書き方
int[] array = Enumerable.Repeat(value,10).ToArray();
List<int> list = Enumerable.Repeat(value,10).ToList();
//...

連番コレクションを作る
コレクション式
//0から10の連番コレクションを作る
TCollection a = [.. Enumerable.Range(0,10)];
古い書き方
int[] array = Enumerable.Range(0,10).ToArray();
List<int> list = Enumerable.Repeat(0,10).ToList();
//...

コレクションを分割して前後入替
コレクション式
TCollection c = [1,2,3,4,5,6];
c = [ ..c[index.. ], ..c[ ..index] ];

コレクションの先頭や末尾に要素を追加
コレクション式
TCol c = [/*...*/];
//先頭に追加
c = [elem, .. c];
//末尾に追加
c = [..c, elem];
古い書き方
配列の場合
T[] c = new T[] { /*...*/ };
T elem = /* 新しい要素 */;
// 先頭に追加
T[] newArray1 = new T[c.Length + 1];
newArray1[0] = elem;
Array.Copy(c, 0, newArray1, 1, c.Length);
c = newArray1;
// 末尾に追加
T[] newArray2 = new T[c.Length + 1];
Array.Copy(c, 0, newArray2, 0, c.Length);
newArray2[^1] = elem; // または newArray2[newArray2.Length - 1]
c = newArray2;

コレクションから指定indexの要素を削除
コレクション式
TCollection a = [1,2,3,4,5,6];
int index = 1 /*set index*/;
a = [ .. a[..index], .. a[(index+1)..] ];

コレクションの指定indexに要素を追加
コレクション式
TCollection a = [1,2,3,4,5,6];
int index = 1 /*insert index*/;
a = [.. a[.. index], 999, .. a[index ..] ];

TakeLast()
/ SkipLast()
の代わり
LINQのTakeLast()
/ SkipLast()
と同じようなことをLINQの対象ではないコレクション(Span<T>
とか)に対してもできる。
コレクション式※
TCollection a = [1,2,3,4,5,6];
var count = 2;
TakeLast()
var b = a[^count..];
SkipLast()
var b = a[..^count];
正確にはこれはコレクション式ではなく、Index/Rangeのインデックスアクセス。
なのでC#8.0から使える。
TakeLast().ToArray()
などのようにキャストを伴う場合の代わりにはコレクション式を使う。
要素のキャストを伴う場合
TCollectionB b = [.. a[^count..]];

ディクショナリの空初期化
コレクション式はディクショナリの初期化はできないが、空の初期化だけは例外的にできる。
コレクション式
Dictionary<K, V> dic = [];

LINQの再現
LINQに対応していない一部のコレクション(例:Span<T>
)でも同等のことができる。
LINQ メソッド | コレクション式での再現方法 | 備考 |
---|---|---|
Cast<T> | [..source] |
型変換が不要な場合のみ |
First | source[0] |
空の場合は例外発生 |
FirstOrDefault | source is [var first, ..] ? first : default |
空の場合 default
|
Last | source[^1] |
空の場合は例外発生 |
LastOrDefault | source is [.., var last] ? last : default |
空の場合 default
|
Take(n) | source[..n] |
n が長さを超えると全体 |
Skip(n) | source[n..] |
n が長さを超えると空 |
ElementAt(i) | source[i] |
範囲外なら例外発生 |
ElementAtOrDefault(i) | source is var s && i < s.Length ? s[i] : default |
範囲外なら default
|
Concat | [..source, ..appendCollection] |
複数コレクションを結合 |
Append(item) | [..source, item] |
末尾に要素を追加 |
Prepend(item) | [item, ..source] |
先頭に要素を追加 |

コレクション式内でクエリ式
List<int> list = [0, 1, 2, 3];
ImmutableList<int> newlist = [.. from item in list where item > 0 select item];
Console.WriteLine( string.Join(",", newlist) ); // 1,2,3