1

アイテムのリストをランダム化するために、このコードをWebサイトから入手しました。[これは、ユーザーが新たに訪問するたびに曲(リスト)をランダム化する音楽プレーヤー用です。したがって、過去の訪問で聞いたのと同じ曲から始めて退屈することはありません]

    $(document).ready(function(){
      $('ul').each(function(){
            // get current ul
            var $ul = $(this);
            // get array of list items in current ul
            var $liArr = $ul.children('li');
            // sort array of list items in current ul randomly
            $liArr.sort(function(a,b){
                  // Get a random number between 0 and 10
                  var temp = parseInt( Math.random()*10 );
                  // Get 1 or 0, whether temp is odd or even
                  var isOddOrEven = temp%2;
                  // Get +1 or -1, whether temp greater or smaller than 5
                  var isPosOrNeg = temp>5 ? 1 : -1;
                  // Return -1, 0, or +1
                  return( isOddOrEven*isPosOrNeg );
            })
            // append list items to ul
            .appendTo($ul);            
      });
});

Chromeブラウザでサイトを開くと、これは完全に正常に機能します。並べ替えはかなり頻繁に行われるため、リストが大幅にランダム化されていることがわかりました。

しかし、FirefoxとIEでは、ソートは十分に行われていません。最初のリスト項目は、10回の試行のうち7回で最初のままであることがわかります。そして、私は他の多くのアイテムについても同じことを見ることができました。例:アイテム#5は、10回の試行のうち5回で3番目の位置に発生します。これらの観察から、JSコードがIEとFirefoxで正しく機能していないことがわかりました。(エンジンの違いにより、異なるブラウザがJSコードを処理する方法が原因である可能性があります)

さて、すべてのブラウザで動作するようにJSコードを変更できるものはありますか?

または、JSを使用して実装した場合に、すべてのブラウザーで適切な並べ替えを行う、他のより優れた並べ替えアルゴリズムはありますか?

2番目の質問の一部がSE内の他の質問で回答されていることは理解していますが、それらの質問の「ブラウザーの互換性」の部分については見つかりませんでした。

助けてくれてありがとう。

4

3 に答える 3

3

あなたのランダム化はあまり良くありません:

// Get a random number between 0 and 10
var temp = parseInt( Math.random()*10 );
// Get 1 or 0, whether temp is odd or even
var isOddOrEven = temp%2;
// Get +1 or -1, whether temp greater or smaller than 5
var isPosOrNeg = temp>5 ? 1 : -1;
// Return -1, 0, or +1
return( isOddOrEven*isPosOrNeg );

つまり、半分のケースで が返さ0れ、2 つの項目が等しいことが sort 関数に伝えられます。優れたソート機能は、それを認識し、再度尋ねることはありません。少数のアイテムしかない場合、アイテムが適切にソートされない可能性が非常に高くなります。これは、比較関数が呼び出される頻度をカウント (ログ) することで証明できます。

+1また、 、0またはのみを返す必要はありません-1。任意の正または負の数値を返すことができます (以下も参照)。ランダム化の場合、実際に等値を返す必要はありません。したがって、代わりにこれを使用します。

….sort( function() {
     return 0.5 - Math.random(); // that would be enough!
} );

ただし、sortランダム化には使用しないでください。Math.random全体の順序付けにはつながらず、そのための並べ替えは行われません: ( EcmaScript 仕様より)

[…] がこの配列の要素の一貫した比較関数でない場合comparefn、並べ替えの動作は実装定義です。

セット内のすべての値、、および(おそらく同じ値)について以下のすべての要件が満たされている場合、関数comparefnは値のセットに対する一貫性のある比較関数です。(いずれかの符号の)手段; と を意味します。SabcSa <CF bcomparefn(a,b) < 0a =CF bcomparefn(a,b) = 0a >CF bcomparefn(a,b) > 0

特定の値のペアが指定され、その 2 つの引数として呼び出された場合、呼び出しはcomparefn(a,b)常に同じ値を返します。さらに、は Number であり、 ではありません。これは、 、、およびの 1 つだけが、との特定のペアに対して真であることを意味することに注意してください。vabType(v)vNaNa <CF ba =CF ba >CF bab

  • を呼び出しcomparefn(a,b)ても、このオブジェクトは変更されません。
  • a =CF a(反射性)
  • ならa =CF b(b =CF a対称)
  • もしa =CF bそしてb =CF cならa =CF c( の推移性=CF)
  • もしa <CF bそしてb <CF cならa <CF c( の推移性<CF)
  • もしa >CF bそしてb >CF cならa >CF c( の推移性>CF)

注: 上記の条件はcomparefn、 がセットSを同値クラスに分割し、これらの同値クラスが完全に順序付けられていることを確認するために必要かつ十分です。

これらのプロパティが満たされていない場合、最適化された並べ替え関数は簡単に失敗する可能性があります。これは、並べ替えがまったく行われないだけでなく、並べ替えが終了しないことを意味する場合もあります。シャッフルに JavaScript Array.sort() メソッドを使用するのは正しいですか? を参照してください。

代わりに、標準のシャッフル アルゴリズムを使用してください。多くの優れたアルゴリズムがあります。Fisher-Yates-Shuffle の実装は非常に簡単です。たとえば、JavaScript 配列をランダム化 (シャッフル) する方法は? .

于 2012-12-21T06:24:03.453 に答える
1

問題はシャッフル方法です。それを修正する簡単ですが、それでも間違った方法は、ソート関数全体をに変更することですreturn Math.random() < 0.5 ? 1 : -1;。ただし、リストが適切にランダム化されることは保証されていません(要素は、50%の確率で上に移動しますが、真のシャッフルでは、元々その上にある要素の数に比例する確率で上に移動します)。

正しいことは、Fisher-Yatesシャッフルを実装することです。これもO(n log n)ではなくO(n)です。

于 2012-12-21T06:25:41.547 に答える
1

この場合の問題は入力です。

parseInt( Math.random()*10 ) は常に偶数を返すため、ランダム化関数をトスに使用します。

このリンクで見つけた似たようなもの。それも役立つことを願っています。

Safari では、IE7 と 8 の Math.random() もランダムではないと思いますか?

于 2012-12-21T06:17:44.977 に答える