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] 先頭に要素を追加