質問
まず、い知のフィッシャー-イェーツ選択することができますが可能な引数の日本酒をしたいユーザーが選択ソートのオプションのドロップダウンリスト。このリストを含む"ランダム"のオプションです。結果に基づいた選択ていただきたいと思い代替にIComparerインスタンスのための私の並べ替えができます。うIComparer音も聞こえてきます。
Googleするアイテムとして、多くの欠陥のある結果がすべてこのフォーム:
public class NaiveRandomizer<T> : IComparer<T>
{
private static Random rand = new Random();
public int Compare(T x, T y)
{
return (x.Equals(y))?0:rand.Next(-1, 2);
}
}
しかし、その実装に偏りがあるまでも例外をスローの一部。バイアス実証することができ、以下のコード:
void Test()
{
Console.WriteLine("NaiveRandomizer Test:");
var data = new List<int>() {1,2,3};
var sortCounts = new Dictionary<string, int>(6);
var randomly = new NaiveRandomizer<int>();
for (int i=0;i<10000;i++)
{ //always start with same list, in _the same order_.
var dataCopy = new List<int>(data);
dataCopy.Sort(randomly);
var key = WriteList(dataCopy);
if (sortCounts.ContainsKey(key))
sortCounts[key]++;
else
sortCounts.Add(key, 1);
}
foreach (KeyValuePair<string, int> item in sortCounts)
Console.WriteLine(item.Key + "\t" + item.Value);
}
string WriteList<T>(List<T> list)
{
string delim = "";
string result = "";
foreach(T item in list)
{
result += delim + item.ToString();
delim = ", ";
}
return result;
}
定できるようになりましたかを実装するランダム IComparer<T>
ることで解決。できる電話 .Sort()
使用には別IComparerインスタンスは、と思いますか他に方法はないこ項目 必要 比較されるもの、真にランダムな値がその価値 必要 も一致する項目内の並べ替え動作します。
い開始 こちらの, が、あくまでも掲載急、 非常に 遅くなっても返却できな(試験を取り入れるとともに、ほこりの少なくともを排除しない場合はカウントのごすことができました。私は期待してはいけませんO(n)のパフォーマンスのようなフィッシャー-イェイツがしたいと思い何かの合理的な(n log nのために小さっぽn)さんに期待していることの表れであョ全のひとつに違いありません。残念ながら、このリンクは、現在の受け答えでの質問では今の交換はできなかった。
ないこれマグネットのためのすべてのgoogleのクエリをお探しIComparable解いただ起こくかえしてご利用いただけることがないよう、正しい情報です。
解決 2
一提案んどでした個IArrangerインターフェイスを記述し単操作 手配 コレクションに納めるものです。この働きがIComparer/IComparableできないので、コレクション全体ではなく、個別の項目です。このようになります:
public interface IArranger<T>
{
IEnumerable<T> Arrange(IEnumerable<T> items);
}
そしてこれを実施 Shuffle
からIArrangerンインタフェースを適切にフィッシャー-イェイツアルゴリズムも実装をラップ追加 IEnumerable.Sort()/IComparable/IComparer
多い。このようになります:
public class ComparerArranger<T> : IArranger<T>
{
private IComparer<T> comparer;
public ComparableArranger(IComparer<T> comparer)
{
this.comparer = comparer;
}
public IEnumerable<T> Arrange(IEnumerable<T> items)
{
return items.OrderBy(i => i, comparer);
}
}
または
//uses the default Comparer for the type (Comparer<T>.Default)
public class TypeArranger<T> : IArranger<T>
{
public IEnumerable<T> Arrange(IEnumerable<T> items)
{
return items.OrderBy(i => i);
}
}
または
public class ShuffleArranger<T> : IArranger<T>
{
//naive implementation for demonstration
// if I ever develop this more completely I would try to
// avoid needing to call .ToArray() in here
// and use a better prng
private Random r = new Random();
public IEnumerable<T> Arrange(IEnumerable<T> items)
{
var values = items.ToArray();
//valid Fisher-Yates shuffle on the values array
for (int i = values.Length; i > 1; i--)
{
int j = r.Next(i);
T tmp = values[j];
values[j] = values[i - 1];
values[i - 1] = tmp;
}
foreach (var item in values) yield return item;
}
}
最終段階を追加することへのIEnumerableよ延長方法。その後も単純な実行時のアルゴリズムの入れ替え、より良い実装のシャッフルアルゴリズムのコードを使い自然:
public static IEnumerable<T> Arrange(this IEnumerable<T> items, IArranger<T> arranger)
{
return arranger.Arrange(items);
}
他のヒント
私は<のhref = "https://stackoverflow.com/questions/554587/is-there-an-easy-way-to-randomize-a-list-in-vb-net/" にやや驚きました>どのように多くの間違った答えにこのスレッドを投稿しました。ただ、OPによって投稿1と同様の解決策を考え出す他人のために、次のコードは、が見えますの正しいます:
int[] nums = new int[1000];
for (int i = 0; i < nums.Length; i++)
{
nums[i] = i;
}
Random r = new Random();
Array.Sort<int>(nums, (x, y) => r.Next(-1, 2));
foreach(var num in nums)
{
Console.Write("{0} ", num);
}
ただし、コードは時折例外をスローしますが、常にではありません。それはあなたが示すエラーを得るでしょう、あなたが50かそこら回を十分な回数は、それを実行、またはループにソート手順を実行する場合:)デバッグすることが楽しく作るものです。
IComparer (or the IComparable methods it relies upon) did not return zero when Array.Sort called x. CompareTo(x). x: '0' x's type: 'Int32' The IComparer: ''.
言い換えれば、クイックソートは、自分自身にいくつかの数字x
を比較し、非ゼロの結果を得ました。コードへの明白な解決策は、書き込みになります:
Array.Sort<int>(nums, (x, y) =>
{
if (x == y) return 0;
else return r.NextDouble() < 0.5 ? 1 : -1;
});
しかし、.NETは、A> B、B> C、およびC> A(おっと!)として矛盾した結果を返す互いに対して3つの数字を比較する機会があるので、これでも、動作しません。あなたがGUID、GetHashCodeメソッド、または任意の他のランダムに生成された入力を使用している場合に関係なく、上記の図のような解決策はまだ間違っています。
<時間>それは言われているでは、フィッシャー・イエーツはシャッフル配列の標準的な方法ですので、最初の場所でのIComparerを使用する本当の理由はありません。たIComparerを使用して、任意の実装はクイックソートがOの時の複雑さを(N Nログ)を有するシーンを尻使用に対しフィッシャーイエーツ(n)はOです。この種の問題を解決するために、よく知られた、効率的な、標準アルゴリズムを使用するだけではなく、全く正当な理由はありません。
あなたのソートしかし、あなたは本当に、たIComparerとランドを使用して主張ならば、の前に、ランダムなデータを適用します。あなたは、ランダムなデータを失うことはありませんので、これは別のオブジェクトへのデータの投影を必要とします:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Pair<T, U>
{
public T Item1 { get; private set; }
public U Item2 { get; private set; }
public Pair(T item1, U item2)
{
this.Item1 = item1;
this.Item2 = item2;
}
}
class Program
{
static void Main(string[] args)
{
Pair<int, double>[] nums = new Pair<int, double>[1000];
Random r = new Random();
for (int i = 0; i < nums.Length; i++)
{
nums[i] = new Pair<int, double>(i, r.NextDouble());
}
Array.Sort<Pair<int, double>>(nums, (x, y) => x.Item2.CompareTo(y.Item2));
foreach (var item in nums)
{
Console.Write("{0} ", item.Item1);
}
Console.ReadKey(true);
}
}
}
またはあなたの悪い自己とLINQyを取得します:
Random r = new Random();
var nums = from x in Enumerable.Range(0, 1000)
orderby r.NextDouble()
select x;
たIComparer を必要とする(Tの同じインスタンスの)いくつかの点でゼロ復帰は、フィッシャーイェーツシャッフルを模倣するジェネリックたIComparerを作成すること、数学的に不可能統計的に。常にバイアスがあるでしょう。本物のシャッフルのために、あなたは、任意の特定の値を返すために、それを強制したいことがありませんでした。
どのように事前に割り当てられたランダムな値である隠しフィールドに基づいてソート「試合?
ジェームズ・カランのアイデアにフォローアップするには、次のIComparerは、リストなどの値を「ソート」を維持しましょう。新しい値が発生した場合、ランダムな位置にあるリストに挿入します。リストインデックスによって比較します。バランスの取れた木か何かのようなリストを維持することによって最適化します。あなたがランダムソートが一貫して同じランダム順序または異なる1毎回とするとの選択肢を持っているので、そのようなたIComparerのすべてのインスタンスは、一貫して、ランダムな並び順を維持します。あなたがそのように「ランダム」読むことを好む場合はマイナー変更であっても、同じ要素が異なる順序位置に「並べ替え」できるようになります。
面白い試み。最も可能性が高いのIComparerの誤用/濫用ます。
あなたはその目的のために構築されていなかったメカニズムを使用してランダム加重並べ替えを行うことをしようとしている。
なぜ、独自のソート・ルーチンと独自の比較子を実装していませんか?私もそれが不十分であるという感覚を持っています。
わからないないのである。
すべてのアルゴリズムを提案し、これまで紹介しある種のバイアスへの出力(一部よりも大きます。
@姫@ルの提案を格納する乱数のデータです。したりする可能性がありますのでいずれのランダム番号が同じ値として、ソート順とさず偏
最悪の場合この場合に分別のルーチンアウトルックは"安定的"(そのオブジェクトと等しい出力と同じ順序で入力します。配列に格納します。うなことが起こる安定して使用すQuickSort内)がありバイアスがいつの項目と同じ値に依存するが、入力特異的にも相対的にQuickSortのピボット).
としてキースペースのためこの乱数の増加の程度の確かさで衝突されていると乱数の発生源でこの数値でソートが、お誕生日パラドックスに至るlikelyhoodの少なくとも一つのペアの中でも衝突が上がります。
のための整数にキーが2^32独自の価値観のもと仮定が完璧にでも分布のランダム値は、75,000行が50%の確率がありますの衝突. Wikipedia.
の暗号化ハッシュアプローチするご提案可能性は十分な大きさでキースペース(160)ビットのうち同士の衝突を無視できるが、アルゴリズムを分解する乱数の発生源があり、単一のint前に比べる否定の利益が大きいキースペース.
最良のアプローチにつ"sortOrder"価値とそれぞれのデータをシャッフルはこれらの値を利用実績のあるアルゴリズム、その結果を受け持つことになります。
ご利用の場合配列になります。ソートが過負荷のかかる配列の"キー"は、配列の値を、"キーの配列はソートされ、通常はがきの値をキー配列が移動し、対応するエントリの値の配列が移転しました。
のようなもの:
Something[] data;//populated somewhere
int[] keys = new int[data.Length];//or long if you might have lots of data
for(int i=0;i<keys.Length;++i) {
keys[i] = i;
}
Shuffle(keys);
Array.Sort(keys, data);