2016-03-06T01:05:28の更新内容

programming/netfx/arrays/3_arraysegment/index.wiki.txt

current previous
1,140 1,73
~
${smdncms:title,部分配列}
${smdncms:title,System.ArraySegment}
~
${smdncms:keywords,System,ArraySegment,Array.Slice,配列,部分配列}
${smdncms:keywords,System,ArraySegment,配列,部分配列}
 
${smdncms:document_versions,codelang=cs,codelang=vb}
${smdncms:document_versions,codelang=cs,codelang=vb}
 

        

        
-
&msdn(netfx,type,System.ArraySegment`1){ArraySegment};は、配列の一部分(区間)を参照して部分配列をなす構造体。 例えば、「あるbyte配列の10番目から5つ分」といったデータを、ArraySegmentのインスタンス1つで表すことが出来る。
 

        

        
~
#navi(..)
ArraySegmentはオリジナルとなる配列の一部分をコピーは作成せず、直接参照する。 そのためArraySegmentを使えば、配列の一部を別の配列にコピーしてから渡す、といったことをする必要がなくなる。 例えば&msdn(netfx,member,System.Net.Sockets.Socket.Send){Socket.Send()メソッド};では、バッファのうち一部分だけを送信できるようにArraySegment<byte>を引数にとるオーバーロードが用意されている。
 

        

        
~
&msdn(netfx,type,System.ArraySegment`1){ArraySegment<T>構造体};を使うと、オリジナルの配列の一部分(区間)を参照して部分配列を構成することができます。 例えば、配列``arr``の要素10番目から5つ分を切り出して使いたいといった場合に、[[ArraySegment構造体>#ArraySegment]]を用いることができます。
なお、この構造体はジェネリック型であるため、配列の型は任意の型を指定できる。
+

          
+
ArraySegmentを使うと、配列の一部分をコピーして別の配列に格納する、といった操作を省略あるいは簡略化することができます。 ArraySegment構造体はジェネリック構造体であるため、任意の型の配列に対して用いることができます。 ArraySegment構造体はオリジナルの配列を切り出した''コピー''を作成するものではなく、オリジナルの配列に対する''ビュー''として動作します。
+

          
+
.NET Frameworkでは、Array.Sliceといった配列の一部分をコピーして部分配列を作成するようなメソッドは用意されていないため、[[Array.Copyメソッドを使って実装する>#slice_array]]などする必要があります。
+

          
+
ここでは、オリジナルの配列のビューとして機能する部分配列を構成する[[ArraySegment構造体>#ArraySegment]]についてと、オリジナルの配列を[[コピーして部分配列を作成する方法>#slice_array]]について解説します。
 

        

        
 
#relevantdocs
#relevantdocs
 

        

        
~
-[[programming/netfx/arrays/2_operations#Array.Copy]]
-[[programming/netfx/arrays]]
~
-[[programming/netfx/collections/2_generic_1_list]]
-[[programming/netfx/collections]]
+
-[[programming/netfx/property#indexer]]
+
-[[programming/netfx/cloning]]
 

        

        
 
#relevantdocs-end
#relevantdocs-end
 

        

        
 
#adunit
#adunit
 

        

        
-
*主なコンストラクタ
-
:ArraySegment(T[] &var{array};, int &var{offset};, int &var{count};)|任意の型の配列&var{array};、区間を定義する最初のインデックス&var{offset};、区間を定義する要素の数&var{count};を指定してインスタンスを生成する。
 

        

        
~
*ArraySegment構造体 [#ArraySegment]
*主なプロパティ
~
**概略
:T[] &msdn(netfx,member,System.ArraySegment`1.Array){Array};|参照される配列。 Tはジェネリック型。 コンストラクタで指定した配列と同じものが返される。
~
PerlやRubyなどの言語では、配列から部分配列を切り出すための以下のような構文が用意されています。
:int &msdn(netfx,member,System.ArraySegment`1.Offset){Offset};|区間内の最初のインデックス。
~

          
:int &msdn(netfx,member,System.ArraySegment`1.Count){Count};|区間内の要素の数。
+
#column
+
#code(perl,type=fragment,部分配列の切り出し(Perl)){{
+
@arr = (0, 1, 2, 3, 4, 5);
+
@segment = @arr[2..4]; # from 2 to 4
+

          
+
print "@arr\n";
+
print "@segment\n";
+
}}
+

          
+
#prompt(実行結果){{
+
0 1 2 3 4 5
+
2 3 4
+
}}
+
#column
+
#code(ruby,type=fragment,部分配列の切り出し(Ruby)){{
+
arr = [0, 1, 2, 3, 4, 5]
+
segment = arr[2..4] # from 2 to 4
+

          
+
p array
+
p segment
+
}}
+

          
+
#prompt(実行結果){{
+
[0, 1, 2, 3, 4, 5]
+
[2, 3, 4]
+
}}
+
#column
+
#code(python,type=fragment,部分配列の切り出し(Python)){{
+
lst = [0, 1, 2, 3, 4, 5]
+
segment = lst[2:5] # from 2 until 5
+

          
+
print lst
+
print segment
+
}}
+

          
+
#prompt(実行結果){{
+
[0, 1, 2, 3, 4, 5]
+
[2, 3, 4]
+
}}
+
#column-end
 

        

        
~
C#やVBなどの言語では部分配列を切り出すような構文は用意されていませんが、ArraySegment構造体を用いるとこれに似た操作を行うことができます。
*使用例
-
ArraySegmentを用いて配列の区間を定義し、その区間内にある要素を表示する。
 

        

        
~
#tabpage(codelang=cs,container-title=ArraySegment構造体を使って部分配列を構成する)
#tabpage(codelang=cs)
 
#code{{
#code{{
 
using System;
using System;
 

        

        
~
class Sample {
class Sample
~
  static void Main()
{
-
  public static void Main()
 
  {
  {
~
    var arr = new int[] {0, 1, 2, 3, 4, 5};
    // byte型の配列を作成し適当なデータを入れる
-
    byte[] buffer = new byte[byte.MaxValue + 1];
 

        

        
~
    // 配列arrのインデックス2から3つ分の要素を参照する部分配列を作成する
    for (int index = 0; index <= byte.MaxValue; index++)
~
    var segment = new ArraySegment<int>(arr, 2, 3); // from 2 length 3
    {
-
      buffer[index] = (byte)(byte.MaxValue - index);
-
    }
 

        

        
~
    // C#では以下のような構文は用意されていない
    // bufferの0x40バイト目から0x10バイト分の区間
~
    //var segment = arr[2..4];
    ArraySegment<byte> segment = new ArraySegment<byte>(buffer, 0x40, 0x10);
 

        

        
~
    Console.WriteLine(string.Join(", ", arr));
    // 区間内の値を表示する
~
    Console.WriteLine(string.Join(", ", segment));
    OutputArraySegment(segment);
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
 

        

        
~
Class Sample
    // bufferの0xf0バイト目から0x10バイト分の区間
~
  Shared Sub Main()
    segment = new ArraySegment<byte>(buffer, 0xf0, 0x10);
+
    Dim arr() As Integer = New Integer() {0, 1, 2, 3, 4, 5}
 

        

        
~
    ' 配列arrのインデックス2から3つ分の要素を参照する部分配列を作成する
    // 区間内の値を表示する
~
    Dim segment As New ArraySegment(Of Integer)(arr, 2, 3) ' from 2 length 3
    OutputArraySegment(segment);
~

          
  }
+
    ' VBでは以下のような構文は用意されていない
+
    'Dim segment() As Integer = arr(2..4)
+

          
+
    Console.WriteLine(String.Join(", ", arr))
+
    Console.WriteLine(String.Join(", ", segment))
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
0, 1, 2, 3, 4, 5
+
2, 3, 4
+
}}
+

          
+
**部分配列の操作
+
ArraySegment構造体では、配列と同様に``foreach``による要素の列挙を行うことができます。
 

        

        
~
#tabpage(codelang=cs,container-title=foreachを使ってArraySegment内の要素を列挙する)
  private static void OutputArraySegment(ArraySegment<byte> segment)
+
#code{{
+
using System;
+

          
+
class Sample {
+
  static void Main()
 
  {
  {
~
    var arr = new int[] {0, 1, 2, 3, 4, 5};
    Console.WriteLine("Length: {0}", segment.Array.Length);
~
    var segment = new ArraySegment<int>(arr, 2, 3);
    Console.WriteLine("Offset: {0}", segment.Offset);
-
    Console.WriteLine("Count:  {0}", segment.Count);
 

        

        
~
    // foreachによる列挙
    for (int index = segment.Offset; index < (segment.Offset + segment.Count); index++)
~
    foreach (var e in segment) {
    {
~
      Console.Write("{0}, ", e);
      Console.Write("0x{0:X2} ", segment.Array[index]);
 
    }
    }
-

          
 
    Console.WriteLine();
    Console.WriteLine();
 
  }
  }
 
}
}
144,76 77,36
 
Imports System
Imports System
 

        

        
 
Class Sample
Class Sample
~
  Shared Sub Main()
  Public Shared Sub Main()
~
    Dim arr() As Integer = New Integer() {0, 1, 2, 3, 4, 5}
    ' byte型の配列を作成し適当なデータを入れる
~
    Dim segment As New ArraySegment(Of Integer)(arr, 2, 3)
    Dim buffer(Byte.MaxValue) As Byte
 

        

        
~
    ' For Eachによる列挙
    For index As Integer = 0 To Byte.MaxValue
~
    For Each e As Integer In segment
      buffer(index) = Byte.MaxValue - index
+
      Console.Write("{0}, ", e)
 
    Next
    Next
+
    Console.WriteLine()
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
 

        

        
~
#prompt(実行結果){{
    ' bufferの&h40バイト目から&h10バイト分の区間
~
2, 3, 4, 
    Dim segment As New ArraySegment(Of Byte)(buffer, &h40, &h10)
+
}}
 

        

        
-
    ' 区間内の値を表示する
-
    OutputArraySegment(segment)
 

        

        
-
    ' bufferの&hF0バイト目から&h10バイト分の区間
-
    segment = New ArraySegment(Of Byte)(buffer, &hF0, &h10)
 

        

        
~
ArraySegment構造体はインデクサを直接サポートしないので、インデックスを使ったアクセスはできません。 ArraySegmentでインデックスを使った要素へのアクセスを行いたい場合は、ArraySegmentを&msdn(netfx,type,System.Collections.Generic.IReadOnlyList`1){IReadOnlyList<T>インターフェイス};(System.Collections.Generic名前空間)にキャストして用います。 IReadOnlyList<T>にキャストした場合も、``foreach``によって列挙することができます。
    ' 区間内の値を表示する
-
    OutputArraySegment(segment)
-
  End Sub
 

        

        
~
#tabpage(codelang=cs,container-title=IReadOnlyListインターフェイスを介して、インデックスによるArraySegment内の要素へのアクセスを行う)
  Private Shared Sub OutputArraySegment(ByVal segment As ArraySegment(Of Byte))
~
#code{{
    Console.WriteLine("Length: {0}", segment.Array.Length)
~
using System;
    Console.WriteLine("Offset: {0}", segment.Offset)
~
using System.Collections.Generic;
    Console.WriteLine("Count:  {0}", segment.Count)
 

        

        
~
class Sample {
    For index As Integer = segment.Offset To segment.Offset + segment.Count - 1
~
  static void Main()
      Console.Write("0x{0:X2} ", segment.Array(index))
~
  {
    Next
+
    var arr = new int[] {0, 1, 2, 3, 4, 5};
 

        

        
+
    // ArraySegmentをIReadOnlyList<T>にキャストして用いる
+
    IReadOnlyList<int> segment = new ArraySegment<int>(arr, 2, 3);
+

          
+
    // インデクサによる要素へのアクセス
+
    Console.WriteLine(segment[0]);
+
    Console.WriteLine(segment[1]);
+
    Console.WriteLine(segment[2]);
+
    Console.WriteLine();
+

          
+
    // IReadOnlyList<T>もforeachによる列挙ができる
+
    foreach (var e in segment) {
+
      Console.Write("{0}, ", e);
+
    }
+
    Console.WriteLine();
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim arr() As Integer = New Integer() {0, 1, 2, 3, 4, 5}
+

          
+
    ' ArraySegmentをIReadOnlyList<T>にキャストして用いる
+
    Dim segment As IReadOnlyList(Of Integer) = New ArraySegment(Of Integer)(arr, 2, 3)
+

          
+
    ' インデクサによる要素へのアクセス
+
    Console.WriteLine(segment(0))
+
    Console.WriteLine(segment(1))
+
    Console.WriteLine(segment(2))
+
    Console.WriteLine()
+
    
+
    For Each e As Integer In segment
+
      Console.Write("{0}, ", e)
+
    Next
 
    Console.WriteLine()
    Console.WriteLine()
 
  End Sub
  End Sub
 
End Class
End Class
221,189 114,51
 
#tabpage-end
#tabpage-end
 

        

        
 
#prompt(実行結果){{
#prompt(実行結果){{
~
2
Length: 256
~
3
Offset: 64
~
4
Count:  16
~

          
0xBF 0xBE 0xBD 0xBC 0xBB 0xBA 0xB9 0xB8 0xB7 0xB6 0xB5 0xB4 0xB3 0xB2 0xB1 0xB0 
~
2, 3, 4, 
Length: 256
-
Offset: 240
-
Count:  16
-
0x0F 0x0E 0x0D 0x0C 0x0B 0x0A 0x09 0x08 0x07 0x06 0x05 0x04 0x03 0x02 0x01 0x00
 
}}
}}
 

        

        
~
#remarks
*インターフェイス
~
インデクサの仕組みについては[[programming/netfx/property#indexer]]を参照してください。
.NET Framework 4.5以降のArraySegmentは、[[IList<T>やIReadOnlyList<T>>programming/netfx/collections/0_abstract]]といったインターフェイスを実装している。 そのため、ArraySegmentが表す部分配列の要素をインデクサを使って参照したり、LINQを使った操作を行ったり、ArraySegmentをコレクションとして扱えるようになっている。
+
#remarks-end
+

          
+

          
 

        

        
~
このほかにも、ArraySegment構造体は&msdn(netfx,type,System.Collections.Generic.IEnumerable`1){IEnumerable<T>};やIReadOnlyList<T>をはじめとして[[コレクションとしてのインターフェイス>programming/netfx/collections/0_abstract]]を複数実装しているので、配列や他のコレクションと同様に扱うことができます。
#tabpage(codelang=cs)
+

          
+
#tabpage(codelang=cs,container-title=ArraySegmentを使って配列の一部分をListに追加する)
+
#code{{
+
using System;
+
using System.Collections.Generic;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    var arr = new int[] {0, 1, 2, 3, 4, 5};
+
    var segment = new ArraySegment<int>(arr, 2, 3);
+

          
+
    var list = new List<int>();
+

          
+
    list.Add(0);
+
    list.Add(1);
+
    list.AddRange(segment); // ListにArraySegmentの内容を追加する
+

          
+
    Console.WriteLine(string.Join(", ", list));
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim arr() As Integer = New Integer() {0, 1, 2, 3, 4, 5}
+
    Dim segment As New ArraySegment(Of Integer)(arr, 2, 3)
+

          
+
    Dim list As New List(Of Integer)()
+

          
+
    list.Add(0)
+
    list.Add(1)
+
    list.AddRange(segment) ' ListにArraySegmentの内容を追加する
+

          
+
    Console.WriteLine(String.Join(", ", list))
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
0, 1, 2, 3, 4
+
}}
+

          
+
また、LINQのメソッドも配列同様に用いることができます。
+

          
+
#tabpage(codelang=cs,container-title=ArraySegmentを使って配列の一部分をListに追加する)
 
#code{{
#code{{
 
using System;
using System;
 
using System.Collections.Generic;
using System.Collections.Generic;
 
using System.Linq;
using System.Linq;
 

        

        
~
class Sample {
class Sample
-
{
 
  static void Main()
  static void Main()
 
  {
  {
~
    var arr = new int[] {0, 1, 2, 3, 4, 5};
    var array = new[] {64, 15, 40, 10, 13, 54, 59, 74, 91, 80};
+
    var segment = new ArraySegment<int>(arr, 2, 3);
 

        

        
~
    // 部分配列内の最大の要素を取得する
    // arrayの部分配列となるArraySegmentを作成
~
    Console.WriteLine("Max() = {0}", segment.Max());
    var segment = new ArraySegment<int>(array, 3, 5);
 

        

        
~
    // 部分配列内の値の合計を求める
    // foreachで列挙
~
    Console.WriteLine("Sum() = {0}", segment.Sum());
    foreach (var val in segment) {
~
  }
      Console.Write("{0}, ", val);
~
}
    }
~
}}
    Console.WriteLine();
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim arr() As Integer = New Integer() {0, 1, 2, 3, 4, 5}
+
    Dim segment As New ArraySegment(Of Integer)(arr, 2, 3)
+

          
+
    ' 部分配列内の最大の要素を取得する
+
    Console.WriteLine("Max() = {0}", segment.Max())
+

          
+
    ' 部分配列内の値の合計を求める
+
    Console.WriteLine("Sum() = {0}", segment.Sum())
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
Max() = 4
+
Sum() = 9
+
}}
 

        

        
-
    // IReadOnlyList<int>にキャストし、インデクサを使って要素を参照
-
    IReadOnlyList<int> list = segment;
 

        

        
-
    for (var i = 0; i < list.Count; i++) {
-
      Console.Write("{0}, ", list[i]);
-
    }
-
    Console.WriteLine();
 

        

        
~
ArraySegmentは配列の一部分を''コピーして切り出すものではなく''、配列の一部分を参照する''ビュー''として動作します。 したがって、オリジナルの配列に対する変更は、ArraySegmentにも影響します。 また、その逆も同様に影響します。
    // 部分配列内の最大値・最小値を求める
~

          
    Console.WriteLine("segment.Max() = {0}", segment.Max());
~
#tabpage(codelang=cs,container-title=ArraySegmentが参照するオリジナルの配列に変更を加える)
    Console.WriteLine("segment.Max() = {0}", segment.Min());
+
#code{{
+
using System;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    var arr = new int[] {0, 1, 2, 3, 4, 5};
+
    var segment = new ArraySegment<int>(arr, 2, 3);
+

          
+
    Console.WriteLine(string.Join(", ", segment));
+

          
+
    // segmentが参照しているオリジナルの配列に変更を加える
+
    arr[2] = 9;
+
    arr[3] = 8;
+
    arr[4] = 7;
+

          
+
    // segmentはarrを'参照'しているので、変更はsegmentにも反映される
+
    Console.WriteLine(string.Join(", ", segment));
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim arr() As Integer = New Integer() {0, 1, 2, 3, 4, 5}
+
    Dim segment As New ArraySegment(Of Integer)(arr, 2, 3)
+

          
+
    Console.WriteLine(String.Join(", ", segment))
+

          
+
    ' segmentが参照しているオリジナルの配列に変更を加える
+
    arr(2) = 9
+
    arr(3) = 8
+
    arr(4) = 7
+

          
+
    ' segmentはarrを'参照'しているので、変更はsegmentにも反映される
+
    Console.WriteLine(String.Join(", ", segment))
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
2, 3, 4
+
9, 8, 7
+
}}
+

          
+
#tabpage(codelang=cs,container-title=ArraySegmentからオリジナルの配列に変更を加える)
+
#code{{
+
using System;
+
using System.Collections.Generic;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    var arr = new int[] {0, 1, 2, 3, 4, 5};
+
    IList<int> segment = new ArraySegment<int>(arr, 2, 3);
+

          
+
    Console.WriteLine(string.Join(", ", arr));
+

          
+
    // ArraySegmentのIListインターフェイスを介して
+
    // オリジナルの配列に変更を加える
+
    segment[0] = 9;
+
    segment[1] = 8;
+
    segment[2] = 7;
+

          
+
    Console.WriteLine(string.Join(", ", arr));
 
  }
  }
 
}
}
 
}}
}}
411,284 166,44
 
#code{{
#code{{
 
Imports System
Imports System
 
Imports System.Collections.Generic
Imports System.Collections.Generic
-
Imports System.Linq
 

        

        
 
Class Sample
Class Sample
 
  Shared Sub Main()
  Shared Sub Main()
~
    Dim arr() As Integer = New Integer() {0, 1, 2, 3, 4, 5}
    Dim array() As Integer = New Integer() {64, 15, 40, 10, 13, 54, 59, 74, 91, 80}
+
    Dim segment As IList(Of Integer) = New ArraySegment(Of Integer)(arr, 2, 3)
 

        

        
~
    Console.WriteLine(String.Join(", ", arr))
    ' arrayの部分配列となるArraySegmentを作成
-
    Dim segment As New ArraySegment(Of Integer)(array, 3, 5)
 

        

        
~
    ' ArraySegmentのIListインターフェイスを介して
    ' foreachで列挙
~
    ' オリジナルの配列に変更を加える
    For Each val As Integer In segment
~
    segment(0) = 9
      Console.Write("{0}, ", val)
+
    segment(1) = 8
+
    segment(2) = 7
+

          
+
    Console.WriteLine(String.Join(", ", arr))
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
0, 1, 2, 3, 4, 5
+
0, 1, 9, 8, 7, 5
+
}}
+

          
+
このようにオリジナルの配列を参照する部分配列ではなく、オリジナルをコピーして互いに独立した部分配列を作成したい場合は、[[#slice_array]]で後述するような方法を使用します。
+

          
+

          
+
**.NET Framework 4以前
+
&msdn(netfx4.0,type,System.ArraySegment`1){.NET Framework 4以前のArraySegment};は、IEnumerable<T>やIList<T>などのインターフェイスが一切実装されておらず、配列の区間を定義する程度のごく限定された機能しか持ちません。 (これらのインターフェイスが実装されるのは.NET Framework 4.5以降です。)
+

          
+
したがって、直接列挙したり、インデックスを指定して参照したり、ここまでで述べたような操作を行うことはできません。 .NET Framework 4以前では、以下のプロパティを参照して部分配列を扱うことになります。
+

          
+
:&msdn(netfx,member,System.ArraySegment`1.Array){Arrayプロパティ};|部分配列として参照される配列(オリジナルの配列)。
+
:&msdn(netfx,member,System.ArraySegment`1.Offset){Offsetプロパティ};|部分配列の最初のインデックス。
+
:&msdn(netfx,member,System.ArraySegment`1.Count){Countプロパティ};|部分配列内の要素の数。
+

          
+
#tabpage(codelang=cs,container-title=.NET Framework 4以前でのArraySegment構造体を使った部分配列の操作例)
+
#code{{
+
using System;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    var arr = new int[] {0, 1, 2, 3, 4, 5};
+
    var segment = new ArraySegment<int>(arr, 2, 3);
+

          
+
    // ArraySegmentで表される部分配列内の要素を表示する
+
    for (var index = 0; index < segment.Count; index++) {
+
      Console.Write("{0}, ", segment.Array[segment.Offset + index]);
+
    }
+
    Console.WriteLine();
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim arr() As Integer = New Integer() {0, 1, 2, 3, 4, 5}
+
    Dim segment As New ArraySegment(Of Integer)(arr, 2, 3)
+

          
+
    ' ArraySegmentで表される部分配列内の要素を表示する
+
    For index As Integer = 0 To segment.Count - 1
+
      Console.Write("{0}, ", segment.Array(segment.Offset + index))
 
    Next
    Next
 
    Console.WriteLine()
    Console.WriteLine()
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
2, 3, 4, 
+
}}
+

          
+
**ArraySegmentが用いられるクラス
+
.NET Frameworkにおいては、引数などでArraySegmentを用いるクラスはそう多くありません。
+

          
+
-&msdn(netfx,member,System.Net.Sockets.Socket.Send){Socket.Sendメソッド};・&msdn(netfx,member,System.Net.Sockets.Socket.Receive){Socket.Receiveメソッド};では、送受信バッファを格納する目的でArraySegment<byte>を用いることができます。
+
-&msdn(netfx,member,System.Net.WebSockets.WebSocket.SendAsync){WebSocket.SendAsyncメソッド};・&msdn(netfx,member,System.Net.WebSockets.WebSocket.ReceiveAsync){WebSocket.ReceiveAsyncメソッド};も同様に、送受信バッファを格納する目的で用いられます。
+
-.NET Framework 4.6以降では、[[MemoryStream.TryGetBufferメソッド>programming/netfx/stream/1_2_memorystream#MemoryStream.TryGetBuffer]]が取得した内部バッファを格納する目的でArraySegment<byte>を要求します。
+

          
+
[[Stream.Readメソッド>programming/netfx/stream/0_abstract#Stream.Read]]や[[Stream.Writeメソッド>programming/netfx/stream/0_abstract#Stream.Write]]など、引数で``&var{array};, &var{offset};, &var{count};``のように配列の一部分を表すオフセットと長さを指定するメソッドの方が現状では一般的です。
+

          
+
このような引数を要求するメソッドを作成する場合、オーバーロードのひとつとしてArraySegmentを引数にとるバージョンも用意しておくことにより、利便性を向上させることができます。
+

          
+
*コピーによる部分配列の作成 [#slice_array]
+
JavaScriptなどの言語では、配列の一部分をコピーして部分配列を切り出すための以下のようなメソッドが用意されています。
+

          
+
#code(js,type=fragment,部分配列の切り出し(JavaScript)){{
+
var arr = [0, 1, 2, 3, 4, 5];
+
var subarr = arr.slice(2, 5); // from 2 until 5
+

          
+
console.log(arr);
+
console.log(subarr);
+
}}
+

          
+
#prompt(実行結果){{
+
Array [ 0, 1, 2, 3, 4, 5 ]
+
Array [ 2, 3, 4 ]
+
}}
+

          
+
**Array.Slice [#Array.Slice]
+
[[.NET FrameworkのArrayクラス>programming/netfx/arrays/2_operations]]では、Array.Sliceのようなメソッドが用意されていないため、次の例のように[[Array.Copyメソッド>programming/netfx/arrays/2_operations#Array.Copy]]を使って独自に実装する必要があります。
+

          
+
#tabpage(codelang=cs,container-title=Array.Copyメソッドを使ってSliceメソッドを実装する)
+
#code{{
+
using System;
+

          
+
// 拡張メソッドを定義するクラス
+
static class ArrayExtensions {
+
  // 配列から部分配列をコピーして切り出す拡張メソッド
+
  public static T[] Slice<T>(this T[] arr, int offset, int count)
+
  {
+
    var subarr = new T[count];
+

          
+
    // arrのインデックスoffsetからcount個分の内容をsliceにコピーする
+
    Array.Copy(arr, offset, subarr, 0, count);
 

        

        
~
    return subarr;
    ' IReadOnlyList(Of Integer)にキャストし、インデクサを使って要素を参照
~
  }
    Dim list As IReadOnlyList(Of Integer) = segment
+
}
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    var arr = new int[] {0, 1, 2, 3, 4, 5};
+

          
+
    // 実装した拡張メソッドを使って部分配列を作成する
+
    var subarr = arr.Slice(2, 3);
+

          
+
    Console.WriteLine(string.Join(", ", arr));
+
    Console.WriteLine(string.Join(", ", subarr));
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+

          
+
' 拡張メソッドを定義するモジュール
+
Module ArrayExtensions
+
  ' 配列から部分配列をコピーして切り出す拡張メソッド
+
  <System.Runtime.CompilerServices.Extension> _
+
  Public Function Slice(Of T)(ByVal arr As T(), ByVal offset As Integer, ByVal count As Integer) As T()
+
    Dim subarr(count - 1) As T
+

          
+
    ' arrのインデックスoffsetからcount個分の内容をsliceにコピーする
+
    Array.Copy(arr, offset, subarr, 0, count)
+

          
+
    Return subarr
+
  End Function
+
End Module
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim arr() As Integer = New Integer() {0, 1, 2, 3, 4, 5}
+

          
+
    ' 実装した拡張メソッドを使って部分配列を作成する
+
    Dim subarr() As Integer = arr.Slice(2, 3)
 

        

        
~
    Console.WriteLine(string.Join(", ", arr))
    For i As Integer = 0 To list.Count - 1
~
    Console.WriteLine(string.Join(", ", subarr))
      Console.Write("{0}, ", list(i))
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
0, 1, 2, 3, 4, 5
+
2, 3, 4
+
}}
+

          
+
#remarks
+
この例では、配列型に``Slice``という''拡張メソッド''を追加することにより、配列から直接呼び出せるようなメソッドを作成しています。 拡張メソッドについての詳細は[[programming/netfx/extension_method]]を参照してください。
+
#remarks-end
+

          
+
#remarks
+
この例で用いているArray.Copyでは、各要素の''簡易コピー''が作成されます。 これは、参照型では参照のみがコピーされ、インスタンスのコピーが作成されるわけではないことを意味します。 簡易コピーの動作や詳細コピーの方法などについては[[programming/netfx/cloning]]を参照してください。
+
#remarks-end
+

          
+
#remarks
+
Listクラスでは、[[List.GetRangeメソッド>programming/netfx/collections/2_generic_1_list#List.GetRange]]によってListの一部分をコピーして取得することができます。
+
#remarks-end
+

          
+
**Skipメソッド・Takeメソッド [#Enumerable.Take]
+
配列として取得する必要がなく、単なる列挙や他のコレクションへの格納、LINQでの操作を目的とする場合は、LINQのメソッド&msdn(netfx,member,System.Linq.Enumerable.Skip){Skip};と&msdn(netfx,member,System.Linq.Enumerable.Take){Take};を使うことでも部分配列を切り出すことができます。
+

          
+
#tabpage(codelang=cs,container-title=Skipメソッド・Takeメソッドを使って部分配列を切り出す)
+
#code{{
+
using System;
+
using System.Linq;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    var arr = new int[] {0, 1, 2, 3, 4, 5};
+

          
+
    // arrの最初の2つの要素をスキップし、続く3つの要素を取得して列挙する
+
    foreach (var e in arr.Skip(2).Take(3)) {
+
      Console.WriteLine(e);
+
    }
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Linq
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim arr() As Integer = New Integer() {0, 1, 2, 3, 4, 5}
+

          
+
    ' arrの最初の2つの要素をスキップし、続く3つの要素を取得して列挙する
+
    For Each e As Integer In arr.Skip(2).Take(3)
+
      Console.WriteLine(e)
 
    Next
    Next
~
  End Sub
    Console.WriteLine()
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
2
+
3
+
4
+
}}
+

          
+
さらに、&msdn(netfx,member,System.Linq.Enumerable.ToArray){ToArrayメソッド};を続けて呼びだせば、Skipメソッド・Takeメソッドの結果を配列として取得することもできます。
+

          
+
#tabpage(codelang=cs,container-title=Skipメソッド・Takeメソッドを使って部分配列を取得する)
+
#code{{
+
using System;
+
using System.Linq;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    var arr = new int[] {0, 1, 2, 3, 4, 5};
 

        

        
~
    // arrの最初の2つの要素をスキップし、続く3つの要素を配列として取得する
    ' 部分配列内の最大値・最小値を求める
~
    var subarr = arr.Skip(2).Take(3).ToArray();
    Console.WriteLine("segment.Max() = {0}", segment.Max())
~

          
    Console.WriteLine("segment.Max() = {0}", segment.Min())
+
    Console.WriteLine(string.Join(", ", subarr));
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Linq
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim arr() As Integer = New Integer() {0, 1, 2, 3, 4, 5}
+

          
+
    ' arrの最初の2つの要素をスキップし、続く3つの要素を配列として取得する
+
    Dim subarr() As Integer = arr.Skip(2).Take(3).ToArray()
+

          
+
    Console.WriteLine(String.Join(", ", subarr))
 
  End Sub
  End Sub
 
End Class
End Class
 
}}
}}
 
#tabpage-end
#tabpage-end
 

        

        
 
#prompt(実行結果){{
#prompt(実行結果){{
~
2, 3, 4
10, 13, 54, 59, 74, 
-
10, 13, 54, 59, 74, 
-
segment.Max() = 74
-
segment.Max() = 10
 
}}
}}
 

        

        
+
#remarks
+
上記の例において、ToArrayメソッドの代わりに&msdn(netfx,member,System.Linq.Enumerable.ToList){ToListメソッド};を用いれば、結果を[[List<T>>programming/netfx/collections/2_generic_1_list]]として取得することができます。
+
#remarks-end
+

          
 

        

        
 

        

        
+
#navi(..)