0

説明:

一部の人々が指摘しているように、これは「このコードは大丈夫ですか」というような質問のように見えます。私が実際に興味を持っている主なことは、この方法がどのように機能するかということ.hasOwnPropertyです。
つまり、IE の JScript エンジン (少なくとも 9 未満) は常にハッシュ テーブルを使用するとは限らないため、そのオブジェクトのすべてのプロパティを反復処理し、別のオブジェクトからそれらのプロパティを取得するかどうかを確認するだけだと思います。プロトタイプチェーンの上位。これは公正な仮定ですか?結局のところ: あるレベルでは、すべてのコードがループと分岐に変換されますが、IE がハッシュ テーブル.hasOwnPropertyを実行しない場合、ループを記述する必要がないということは単なる糖分ではないでしょうか?
DCのブログ投稿またはビデオの1つからこの概念を得たと思います。彼が配列について話していた可能性があり、JSでそれらが存在する(または存在する可能性がある)風変わりなものである可能性があります。ビデオ/ブログ投稿 (?) ATM が見つかりません。また、JS 配列は悪用されることが多いため、多くの人が同意すると思いますが、この質問への回答は適切な参考資料として役立つと思いました。そのため、codereview には投稿しませんでした。

現在の回答に関する限り、そして私の質問が間違った角度から始まったので(その背後にあるメカニズムよりもコードに焦点を当てています)、私がしなかった問題を指摘してくれてありがとうございます。のことを考える。


最近、私が取り組んでいたスクリプトの配列プロトタイプを拡張しました (まだ撮影しないでください)。車輪の再発明を避けるために、私は行って、他の人がどのようにそれを行ったかのいくつかの例を探しました.

これは非常に一般的であり、明らかに不必要に複雑です。私はまた、代替案として、ポスターが彼の高速アルゴリズムについてかなり独善的であることを除いて、私はまだ改善の余地があると感じています.

私は独善的な賢者として出くわすかもしれないことを知っています.私のunique方法は実際には次のようになります:

Array.prototype.unique = function()
{
    'use strict';
    var i,obj,ret;
    ret = [];
    obj = {};
    for (i=0;i<this.length;i++)
    {
        if (!obj.hasOwnProperty(this[i]))
        {
            ret.push(this[i]);
            obj[this[i]] = i;
        }
    }
    return ret;
};

このように、私が知る限り、2 番目のループは必要ありませんね。もちろん、hasOwnPropertyメソッドが非常に遅い場合を除きますが、どういうわけか、この場合、チェーンは 1 レベルまでしか戻ることができないのではないかと疑っていObject.prototypeます。

私が投稿した 2 番目のリンクには、いくつかの統計と速度比較が含まれていますが、誰もが知っているように、現実の世界ではほとんど意味がありません。JS とベンチマークに関する優れた記事の方向性を示してくれる人はいますか ( John Resig のブログの記事は別として? )

では、好奇心から: この方法に問題がある人はいますか? さらに詳しい情報: Object.prototype: 変更なし、グローバルなし、フレームワークなし、このメソッドundefinedundefinedやみくもに実装されていません ( if (!Array.prototype.unique){...})

4

3 に答える 3

4

これは、型を正しく考慮し、単純なネストされたループよりもはるかに高速で、元の配列の順序を維持する実装です。

Array.prototype.unique = function(){
    var r, o, i, j, t, tt;
    r = [];
    o = {};
    for(i = 0; i < this.length; i++){
       t = this[i];
       tt = o[t] = o[t] || [];
       for(j = 0; j < tt.length; j++)
           if(tt[j] === this[i])
               break;
       if(j == tt.length)
           r.push(tt[j] = t);
     }
     return r;
}

これらの実装を比較するためにJSPerfを作成しました。

  • unique1はネストされたループです。
  • unique2は、リンクした高速アルゴリズムです。
  • unique3はあなたのバージョンです。
  • unique4は私のものです。
    追加した
  • unique5はKooilncの答えです
  • unique6はprimvdbの答えです

unique2が最速ですが、同等である"1"と見なすという問題があります。1unique4は速度で3番目になりますが、unique1よりもはるかに高速で、正しい出力を提供します。4つのバリエーションはすべて、実際には異なる出力を提供します。

=> [1, "1", 1, 2, 3, 4, 1, 2, 3, "2", "3", "4", "true", "true", true].unique1()
// ["1", 4, 1, 2, 3, "2", "3", "4", "true", true]

=> [1, "1", 1, 2, 3, 4, 1, 2, 3, "2", "3", "4", "true", "true", true].unique2()
// [1, "2", "3", "4", true]

=> [1, "1", 1, 2, 3, 4, 1, 2, 3, "2", "3", "4", "true", "true", true].unique3()
// [1, 2, 3, 4, "true"]

=> [1, "1", 1, 2, 3, 4, 1, 2, 3, "2", "3", "4", "true", "true", true].unique4()
// [1, "1", 2, 3, 4, "2", "3", "4", "true", true]
于 2012-08-20T19:10:38.173 に答える
3

広くサポートされていませんが、Set(ECMAScript Harmonyから)を使用できます。ネイティブであるため、パフォーマンスにそれほど影響を与えることはありません(たとえば、実際のインデックスを探す必要はありindexOfません)。主な利点は、オブジェクトを含め、すでに持っているアイテムを追跡するためにシームレスに使用でき、同じオブジェクトを考慮に入れることができることです。

Array.prototype.unique = function() {
    'use strict';
    var ret = [];
    var used = new Set();
    for (var i = 0; i < this.length; i++) {
        if (!used.has(this[i])) {
            ret.push(this[i]);
            used.add(this[i]);
        }
    }
    return ret;
};

var a = {};
var b = {};
[1, 2, 1, a, a, null, b].unique(); // [1, 2, a, null, b]
于 2012-08-20T18:38:57.517 に答える
0

見た目は問題ありませんが、Felix Klingが指摘したように、プリミティブを含む配列でのみ機能します。これはもう少し複雑ですが、私が思うすべてのタイプで機能します。

Array.prototype.unique = function(){
  'use strict';
  var im = {}, uniq = [];
  for (var i=0;i<this.length;i++){
    var type = (this[i]).constructor.name, 
    //          ^note: for IE use this[i].constructor!
        val = type + (!/num|str|regex|bool/i.test(type) 
               ? JSON.stringify(this[i]) 
               : this[i]);
    if (!(val in im)){uniq.push(this[i]);}
    im[val] = 1;
  }
  return uniq;
}
//testing
var test = [1,2,'string',[1,2,3],'string','1','2',
            {yada:'yada'},/[a-z]/i,2,1,1,2,[1,2,3],
            false, new Date(),/[a-b]/i,5,/[a-z]/i,'false']
   ,testunique = test.unique();
//=> testunique now
//   [1,2,string,[1,2,3],1,2,[object Object],
//    /[a-z]/i,false,Mon Aug 20 2012 20:20:11 GMT+0200,
//    /[a-b]/i,5,false]
于 2012-08-20T18:22:25.407 に答える