2014年06月18日

配列

配列は、同じ型のデータを纏めて扱うための固定長の領域。
可変長を簡単に扱えるコレクションクラスがにより出番は減ったけどまだ重要。
C#(.NET)の配列はSystem.Arrayクラスを暗黙的に継承する参照型
int[] array = new int[] { 100, 200, 300, 400, 500 };
// 添え字でアクセス
int value = array[3];                // 400
// System.Arrayクラスのメンバを使用
int size = array.Length;             //   5
int value2 = (int)array.GetValue(3); // 400
初期化
配列を初期化する文法はいろいろある。
int[] array1 = new int[5];
int[] array2 = new int[5] { 1, 2, 3, 4, 5 };
int[] array3 = new[] { 1,2,3,4,5};   // 宣言と同時の場合
int[] array4 =  {1,2,3,4,5};         // 3.0以降
多次元配列と配列の配列
// 多次元配列 
int[,] array5 = new int[3,5];
// 配列の配列
int[][] array6 = new int[][]{new int[3],new int[5],new int[2]};
引数としての配列
参照渡が必要な場合があり
public static void Tester
{
int[] array7 = { 100, 200, 300, 400, 500 };
int[] array8 = { 100, 200, 300, 400, 500 };

TestFanc(array7);           // 100, 200, 300, 400, 500
TestFancRef(ref array8);    // 1, 2, 3, 4, 5 
}

static void TestFanc(int[] array)
{
   // array[1] = 150; など参照先の中身を変えるならOK
   // この引数のArrayはローカルなので呼び出し元に影響しない
    array = new int[] { 1, 2, 3, 4, 5 };
}
static void TestFancRef(ref int[] array)
{
    array = new int[] { 1, 2, 3, 4, 5 };
}
posted by RR at 23:37 | Comment(0) | 集合 | このブログの読者になる | 更新情報をチェックする

2014年06月20日

System.Collections もう使わないけれど

System.Collections名前空間にて提供されているコレクション群は、ジェネリクスをサポートしたコレクション群の登場により使用する機会はほとんど無くなりました。
それでも重要なものがいくつか。

ArrayList
可変長の配列のようなもの。
ArrayList arrayList = new ArrayList();
arrayList.Add("Red");
arrayList.Add("Blue");
arrayList.Add("Yellow");
arrayList.RemoveAt(1);
int count = arrayList.Count; // 2
HashTable
キーと値の組み合わせの集合
Hashtable hashTable = new Hashtable();
hashTable.Add("us", "United States");
hashTable.Add("jp", "Japan");
hashTable.Add("fr", "France");
string country = (string)hashTable["jp"];      // Japan
bool isExistKey = hashTable.ContainsKey("uk"); // false
foreach(DictionaryEntry entry in hashTable)
{
    Console.WriteLine("KEY:{0},VALUE{1}",entry.Key,entry.Value);
}
Queue
FIFO(先入れ先出し)
Queue queue = new Queue();
queue.Enqueue("AAAA");
queue.Enqueue("BBBB");
queue.Enqueue("CCCC");
string value1 = (string)queue.Dequeue(); // AAAA 先頭の値を削除し取得
string value2 = (string)queue.Peek();    // BBBB 先頭の値を削除せず取得
string value3 = (string)queue.Dequeue(); // BBBB 先頭の値を削除し取得
Stack
LIFO(後入れ先出し )
Stack stack = new Stack();
stack.Push("AAAA");
stack.Push("BBBB");
stack.Push("CCCC");
string value4 = (string)stack.Pop();     // CCCC 最後の値を削除し取得
string value5 = (string)stack.Peek();    // BBBB 最後の値を削除せず取得
string value6 = (string)stack.Pop();     // BBBB 最後の値を削除し取得
コレクションの独自実装
どのクラスやインタフェースを継承すべきかが考慮のしどころでしたが、その機会ももはやないかも。ICollection,IList,IDictionay,DictionaryBase,CollectionBase,ReadOnlyCollectionBaseなどが候補です。

IEnumerableとIEnumeratorインタフェース
IEnumerableはIEnumerator GetEnumerator()というメンバを一つだけ持つインタフェースであり、このインタフェースを継承(実現)しているものがForeach文で使用できることになる。
このメソッドの戻型であるIEnumeratorインタフェースはObject Current{get;} / bool MoveNext() / void Reset();の3をメンバに持つ。
posted by RR at 04:04 | Comment(0) | 集合 | このブログの読者になる | 更新情報をチェックする

2014年06月21日

配列の操作

文字列と配列
stringはIEnumerableインタフェースを継承(実現)しているのでCharの配列しても使えます。
// 文字列
string literal = "ABCDEFG";
// 添字で
char third = literal[3]; // D
// Charの配列への変換
char[] charArray = literal.ToCharArray();
System.Arrayクラス
配列を操作するための処理がSystem.Arrayクラスで提供されています。
以下いくつかサンプルコードです。こんなのが沢山あります。
int[] array1 = { 3,5,1,4,10,8,2,5,10};
// コピー
int[] destArray = new int[3];
Array.Copy(array1,2,destArray,0,3); // destArray:1,4,10
// 並び替え
int[] array2 = { 1,2,3,4,5};
Array.Reverse(array2); // 5,4,3,2,1
ジェネリック
int[] array = { 3,5,1,4,10,8,2,5,10};
// 最初に見つけた偶数
int even = Array.Find(array, i => (i %2 == 0)); // 4
// 配列中のすべての偶数
int[] evenArray = Array.FindAll(array, i => (i % 2 == 0)); // 4,10,8,2,10
スレッドセーフ
配列を操作中に変更されないようロックが必要な場合があります。
int[] array = { 3,5,1,4,10,8,2,5,10};
lock (array.SyncRoot)
{
    int sum = 0;
    for (int count = 0; count < array1.Length; ++count)
    {
        sum += array1[count];
    }
}
LINQ
リンクも使えます。
using System.Linq; // これが必要
int[] array = { 3,5,1,4,10,8,2,5,10};
int sum = array.Sum();
var ret = from i in array where i % 2 == 0 select i;
int[] evenArray = ret.ToArray();
posted by RR at 05:43 | Comment(0) | 集合 | このブログの読者になる | 更新情報をチェックする

2014年06月29日

System.Collections.Generic ジェネリックコレクション

ジェネリック(Generic)
総称的とか汎用的と訳され、処理自体は同一だが型(Type)が異なることを言います。

ここではジェネリックコレクションについての記載しています。ジェネリッククラスやジェネリックメソッドについては別途記載予定です。

ジェネリックではない可変長の配列を扱うArrayListクラスは例えば以下のようになります。
using System.Collections;

           ArrayList arrayList = new ArrayList();
           // 文字列型や数値型を追加することが可能
           arrayList.Add("Red");
           arrayList.Add(100);
           // 値はobject型で取得されるのでキャストが必要
           string value = (string)arrayList[0];

このように、例えば文字列型のみを使用するつもりでも、数値型など他の型も扱えてしまうし、文字列型と判然しているのにキャストが必要となります。

StringCollection
文字列型だけを扱うコレクションが標準ライブラリにはあります。
using System.Collections.Specialized;

            StringCollection stringCollection = new StringCollection();
            stringCollection.Add("Red");
            //stringCollection.Add(100); 文字列型以外はコンパイルエラー
            string value = stringCollection[0]; //キャスト不要


となると、Int型専用コレクションやDateTime型専用や自定義クラス専用なども欲しくなります。
そこで何用なのかを<T>という表記で指定する方式がジェネリックです。Tに該当するTypeを指定します。

System.Collections.Generic
System.Collections名前空間にて提供されていたコレクションのジェネリック版は以下のようになります。
※ここでは文字列型を指定しています。
using System.Collections.Generic;
            // ArrayList は  List<T>
            List<string> list = new List<string>();
            //list.Add(100);  // 文字列型は追加不可(コンパイルエラー)
            list.Add("Red");
            list.Add("Blue");
            list.Add("Yellow");
            list.RemoveAt(1);
            string secondValue = list[1]; // 文字列型が返却されるのでキャスト不要
            int count = list.Count; // 2

            // Hashtable は Dictionary<TKey,TValue>
            Dictionary<string, string> dictionary = new Dictionary<string, string>();
            dictionary.Add("us", "United States");
            dictionary.Add("jp", "Japan");
            dictionary.Add("fr", "France");
            string country = dictionary["jp"];      // Japan
            bool isExistKey = dictionary.ContainsKey("uk"); // false

            // Queue は Queue<T>
            Queue<string> queue = new Queue<string>();
            queue.Enqueue("AAAA");
            queue.Enqueue("BBBB");
            queue.Enqueue("CCCC");
            string value1 = queue.Dequeue(); // AAAA 先頭の値を削除し取得
            string value2 = queue.Peek();    // BBBB 先頭の値を削除せず取得
            string value3 = queue.Dequeue(); // BBBB 先頭の値を削除し取得
            // Stack は Stack<T>
            Stack<string> stack = new Stack<string>();
            stack.Push("AAAA");
            stack.Push("BBBB");
            stack.Push("CCCC");
            string value4 = stack.Pop();     // CCCC 最後の値を削除し取得
            string value5 = stack.Peek();    // BBBB 最後の値を削除せず取得
            string value6 = stack.Pop();     // BBBB 最後の値を削除し取得
HashSet
有限集合に対する各種操作を高パフォーマンスで実現できます。
これは非ジェネリックに該当するのはなし
using System.Collections.Generic;
            HashSet<int> setA = new HashSet<int>() { 1,2,3,4,5};
            HashSet<int> setB = new HashSet<int>() { 1,3,5,7,9};
            // A と B との両方にあるのを抽出
            setA.IntersectWith(setB); // setA:1,3,5
            // その他にも便利メソッドが沢山

その他のコレクション

System.Collections.Generic名前空間には、上記の他にインデックスによるアクセスは出来ないが挿入・削除が速いLinkedListクラス、ソートした順にアクセス可能なSortedコレクション群、スレッドセーフなSynchronizedコレクション群などがあります。
posted by RR at 00:05 | Comment(0) | 集合 | このブログの読者になる | 更新情報をチェックする

2016年03月16日

配列の最大要素数は2^31ではない

配列の添字(Index)はint型なので、その最大値が取れるかと試してみると失敗する。
     var array = new int[int.MaxValue];
上記コードはOutOfMemoryExceptionがスローされる。

その閾値はいくつなのかと調べてみたらMSDNにありました。

https://msdn.microsoft.com/ja-jp/library/system.array.aspx

引用します。(日本語訳はないみたい)
By default, the maximum size of an T:System.Array is 2 gigabytes (GB). In a 64-bit environment, you can avoid the size restriction by setting the enabled attribute of the configuration element to true in the run-time environment. However, the array will still be limited to a total of 4 billion elements, and to a maximum index of 0X7FEFFFFF in any given dimension.

デフォルトの設定では、オブジェクトの最大サイズは2ギガバイトです。64ビット環境の場合、構成ファイルの設定により実行時のこの制限を解除することができます。但し、合計要素数40億の制限はそのままですし、インデックス(添字)の最大数である0X7FEFFFFF(約21億)の制限もそのままです。

つまり、以下の条件を満たす値ということらしい。

・インデックスであるint.MaxValueより小さい
・オブジェクトのサイズが2Gより小さい
・合計要素数(多次元配列等でも)が40億より小さい
(・実行時のヒープに連続使用可能領域がある?)

同一マシンでなんどか試行してみても閾値一致しないし、同一スペックのマシンで試行してもかなり幅がありました。よくわかりません、すいません。

とりあえずInt.MaxValueなんて一度も取れませんでした。
posted by RR at 02:22 | Comment(0) | 集合 | このブログの読者になる | 更新情報をチェックする