Posted at

T型のシーケンスを、任意サイズの配列のシーケンスに変える

More than 5 years have passed since last update.

タイトルから内容が分かりにくいですが、次のようなことをします。

For Each a In Enumerable.Range(1, 10).Buffer(5)

For Each b In a
Console.Write("{0} ", b)
Next
Console.WriteLine()
Next

を実行すると


1 2 3 4 5

6 7 8 9 10


と表示されます。で、タイトルの内容を処理するのが Buffer() です。

IEnumerable(Of T) に拡張メソッドを追加しています。

ソースコードを次に示します。


Buffer.vb


Module EnumerableExBuffer

<Extension>
Public Function Buffer(Of T)(
ByVal source As IEnumerable(Of T),
ByVal count As Integer
) As IEnumerable(Of T())

If source Is Nothing Then Throw New ArgumentNullException("source")
If count < 1 Then Throw New ArgumentOutOfRangeException("count")

Return Buffer_(source, count)
End Function

Private Iterator Function Buffer_(Of T)(
ByVal source As IEnumerable(Of T),
ByVal count As Integer
) As IEnumerable(Of T())

Dim list = New List(Of T)(count)
For Each item In source
list.Add(item)
If list.Count = count Then
Yield list.ToArray()
list.Clear()
End If
Next
If list.Count > 0 Then
Yield list.ToArray()
End If
End Function

End Module


実際にはどんな使い方があるかというと、一例で、文字列"414243444546"を"ABCDEF"に変換するときに

Dim s = Encoding.ASCII.GetString(

"414243444546"
.Buffer(2)
.Select(Function(a) New String(a))
.Select(Function(a) Convert.ToByte(a, 16))
.ToArray())

と書ける。文字列は IEnumerable(Of Char) に変換できるので、.Buffer(2) で 2文字の配列のシーケンスにします。その後、Char の配列から文字列を作成し、Convert.ToByte で16進文字列をバイトに変換し、最後にバイト配列にしています。作成されたバイト配列を ASCII でデコードすれば目的の文字列が得られます。