C#でのInt64インデックスを持つアレイの一部をソートする方法?
質問
.NET Frameworkが1が作用する一種の開始と終了なインデックスを指定することができますのArray.sort過負荷を持っています。しかし、これらのパラメータは、唯一の32ビットです。だから私は、並べ替えの範囲を記述するなインデックスは、64ビットの数値を使用して指定することができたときに大きな配列の一部をソートする方法が表示されません。私は、フレームワークのソートの実装をコピーして修正することができると仮定し、それは理想的ではありません。
アップデートます:
私は、これらおよび他の大規模なアレイの問題を中心に私を助けるために2つのクラスを作成しました。もう一つの、このような問題は、私は私の記憶の限界になったずっと前に、私はOutOfMemoryException例外のを取得を開始ということでした。私は、要求されたメモリが使用可能ですが、連続していない可能性があるため、これがあると仮定しています。だから、私は配列の一般的な、動的にかなりのリストであるクラスBigArrayを、作成しました。これは、フレームワークのジェネリックリストクラスよりも小さなメモリフットプリントを持っており、配列全体が連続している必要はありません。私はパフォーマンスヒットをテストしていませんが、私は確信してその存在します。
public class BigArray<T> : IEnumerable<T>
{
private long capacity;
private int itemsPerBlock;
private int shift;
private List<T[]> blocks = new List<T[]>();
public BigArray(int itemsPerBlock)
{
shift = (int)Math.Ceiling(Math.Log(itemsPerBlock) / Math.Log(2));
this.itemsPerBlock = 1 << shift;
}
public long Capacity
{
get
{
return capacity;
}
set
{
var requiredBlockCount = (value - 1) / itemsPerBlock + 1;
while (blocks.Count > requiredBlockCount)
{
blocks.RemoveAt(blocks.Count - 1);
}
while (blocks.Count < requiredBlockCount)
{
blocks.Add(new T[itemsPerBlock]);
}
capacity = (long)itemsPerBlock * blocks.Count;
}
}
public T this[long index]
{
get
{
Debug.Assert(index < capacity);
var blockNumber = (int)(index >> shift);
var itemNumber = index & (itemsPerBlock - 1);
return blocks[blockNumber][itemNumber];
}
set
{
Debug.Assert(index < capacity);
var blockNumber = (int)(index >> shift);
var itemNumber = index & (itemsPerBlock - 1);
blocks[blockNumber][itemNumber] = value;
}
}
public IEnumerator<T> GetEnumerator()
{
for (long i = 0; i < capacity; i++)
{
yield return this[i];
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
バック仕分けの本来の問題になって...私は本当に必要なものために、配列の各要素に作用する方法でした。しかし、そのような大きなアレイと、それに基づいて行動した後、(元の順序を維持しなければならない)ソートされたコピーを破棄し、データをコピーすること禁止され、ソートこと。だから私は、あなたがソート順に、ソートされていない配列の各要素上で任意の操作を実行することを可能にする静的クラスOrderedOperationを、作成しました。そして、低メモリフットプリント(ここでは、実行時間の取引メモリ)で行ってください。
public static class OrderedOperation
{
public delegate void WorkerDelegate(int index, float progress);
public static void Process(WorkerDelegate worker, IEnumerable<int> items, int count, int maxItem, int maxChunkSize)
{
// create a histogram such that a single bin is never bigger than a chunk
int binCount = 1000;
int[] bins;
double binScale;
bool ok;
do
{
ok = true;
bins = new int[binCount];
binScale = (double)(binCount - 1) / maxItem;
int i = 0;
foreach (int item in items)
{
bins[(int)(binScale * item)]++;
if (++i == count)
{
break;
}
}
for (int b = 0; b < binCount; b++)
{
if (bins[b] > maxChunkSize)
{
ok = false;
binCount *= 2;
break;
}
}
} while (!ok);
var chunkData = new int[maxChunkSize];
var chunkIndex = new int[maxChunkSize];
var done = new System.Collections.BitArray(count);
var processed = 0;
var binsCompleted = 0;
while (binsCompleted < binCount)
{
var chunkMax = 0;
var sum = 0;
do
{
sum += bins[binsCompleted];
binsCompleted++;
} while (binsCompleted < binCount - 1 && sum + bins[binsCompleted] <= maxChunkSize);
Debug.Assert(sum <= maxChunkSize);
chunkMax = (int)Math.Ceiling((double)binsCompleted / binScale);
var chunkCount = 0;
int i = 0;
foreach (int item in items)
{
if (item < chunkMax && !done[i])
{
chunkData[chunkCount] = item;
chunkIndex[chunkCount] = i;
chunkCount++;
done[i] = true;
}
if (++i == count)
{
break;
}
}
Debug.Assert(sum == chunkCount);
Array.Sort(chunkData, chunkIndex, 0, chunkCount);
for (i = 0; i < chunkCount; i++)
{
worker(chunkIndex[i], (float)processed / count);
processed++;
}
}
Debug.Assert(processed == count);
}
}
2つのクラスが(それは私がそれらを使用する方法です)一緒に働くことができますが、彼らがする必要はありません。私は他の誰かが彼らが重宝願っています。しかし、私は、彼らは、フリンジケースクラスです、認めますよ。質問を歓迎します。私のコードを吸うなら、私も、ヒントを聞きたいと思います。
最後にひとつの思考:あなたがOrderedOperationで見ることができるように、私はlong型int型を使用していませんよ。現在、それは私が持っていた元の質問(アプリケーションは、あなたが言うことができない場合には、フラックスである)にもかかわらず、私のために十分です。しかし、このクラスは、同様に、必要が生じた場合long型を処理することができる必要があります。
解決
あなたも、64ビットのフレームワーク上で、配列の要素の最大数はint.MaxValue
であることがわかります。
Int64
を取るか返す既存の方法は、単に内部long
すると、Int32
パラメータはArgumentOutOfRangeException
とlong
の間にない場合は、パラメータの場合には、int.MinValue
をスローしますint.MaxValue
値をキャストします。
たとえばLongLength
プロパティの値を単にキャスト、Int64
を返し、戻りLength
プロパティ
public long LongLength
{
get { return (long)this.Length; } // Length is an Int32
}
だから私の提案はInt64
し、既存のInt32
オーバーロードのいずれかを呼び出すために、あなたのSort
のなインデックスをキャストすることです。
他のヒント
、あなたはそれはそれを戻して、並べ替え、あなたがソートする必要がある部分を引き出すことができます。仮定すると、あなたはもちろん、未満2 ^ 32個の要素をソートしています。
あなたは以上の2 ^ 32の要素をソートしている場合、それはとにかくソートアルゴリズム、より効率的に、あなた自身を記述するのが最善だろうように思えるます。