4

私は、Mike Bostock のクロスフィルター ライブラリを使用して、大きなデータセットをフィルター処理および並べ替えています。私の問題:複数の次元を持つデータセットが与えられた場合、一度に複数の次元で並べ替えるにはどうすればよいですか?

例 JSFiddle

テスト データセット:

[
    { cat: "A", val:1 },
    { cat: "B", val:2 },
    { cat: "A", val:11 },
    { cat: "B", val:5 },
    { cat: "A", val:3 },
    { cat: "B", val:2 },
    { cat: "A", val:11 },
    { cat: "B", val:100 }
]

必要な出力の例、並べ替えcat, val(昇順):

[
    { cat: "A", val:1 },
    { cat: "A", val:3 },
    { cat: "A", val:11 },
    { cat: "A", val:11 },
    { cat: "B", val:2 },
    { cat: "B", val:2 },
    { cat: "B", val:5 },
    { cat: "B", val:100 }
]

これまでに使用したアプローチは、目的の次元で文字列連結を使用することです。

var combos = cf.dimension(function(d) { return d.cat + '|' + d.val; });

これは、複数の文字列ベースのディメンションでは正常に機能しますが、自然な並べ替えではないため、数値ディメンションでは機能しません ( '4' > '11')。数字をゼロで埋めることでこれを機能させることができると思いますが、これは大規模なデータセットでは費用がかかる可能性があるため、避けたいと思います。クロスフィルターを使用して、ここで機能する別の方法はありますか?

さまざまなディメンションにさまざまな並べ替え方向 (昇順/降順) を許可するソリューションのボーナス ポイント。

明確化: はい、ネイティブArray.sort実装に切り替える必要があるかもしれません。しかし、クロスフィルターを使用することの要点は、特に大規模なデータセットの場合に非常に高速であり、並べ替えの繰り返しをさらに高速にする方法で並べ替え順序をキャッシュすることです。だから私はここでクロスフィルターベースの答えを本当に探しています。

4

4 に答える 4

2

crossfilter ライブラリを使用していないことはわかっていますが、これを行うために sort 関数を使用しないのはなぜですか?

var combos = cf.sort(function(a,b) { 
   if(a.cat == b.cat) return a.val < b.val ? -1 : 1;
   return a.cat < b.cat ? -1 : 1;
});

http://jsfiddle.net/cQXNK/5/を参照

異なる次元に異なるソート方向を持たせるには、-1 を 1 に、またはその逆に交換するだけです。

于 2013-01-09T19:43:36.497 に答える
1

を使用するArray.prototype.sortと、次のことができます。

function sortByPriority(a, b) {
    var p = sortByPriority.properties;
    function pad (str, max) {
        str = String(str);
        return str.length < max ? pad("0" + str, max) : str;
    }

    if (!p) {
        return a - b;
    }
    var ar ='', br = '';
    for (var i = 0, max = p.length; i < max; i++) {
        ar += pad(a[p[i]], 10);
        br += pad(b[p[i]], 10);
    }
    return ar == br ? 0 : ar > br ? 1 : - 1;
}

使い方:

cat次に並べ替えval

sortByPriority.properties = ['cat', 'val'];
myArray.sort(sortByPriority);

結果:

  • 1
  • A3
  • A11
  • A11
  • B2
  • B2
  • B5
  • B100

事前に実行したい場合val

sortByPriority.properties = ['val', 'cat'];
myArray.sort(sortByPriority);

結果:

  • 1
  • B2
  • B2
  • A3
  • B5
  • A11
  • A11
  • B100

非常に効果的なコードではありませんが、改善できます。

アップデート:

pad関数を使用して、クロスフィルターを使用して同じ結果を得ることができます。この jsfiddle を見てください

var combos = cf.dimension(function(d) { 
    return pad(d.cat, 10) + '|' + pad(d.val, 10); 
});

「coll」の最大の文字列から同じ長さでパッドのサイズを変更することもできます。これにより、これまでの結果が保証されます。

その最適化を参照してください: http://jsfiddle.net/gartz/cQXNK/7/

于 2013-01-09T20:26:09.967 に答える
1

これが私がやったことです:

  • 私はまだ単一の新しい次元で文字列連結を使用していますが、
  • クロスフィルターを使用して最小値/最大値を取得し、メジャーを文字列に変換する前に、比較可能な正の 10 進数に変換します。

    var vals = cf.dimension(function(d) { return d.val }),
        min = vals.bottom(1)[0].val,
        offset =  min < 0 ? Math.abs(min) : 0,
        max = vals.top(1)[0].val + offset,
        valAccessor = function(d) {
            // offset ensures positive numbers, fraction ensures sort order
            return ((d.val + offset) / max).toFixed(8);
        },
        combos = cf.dimension(function(d) { 
            return d.cat + '|' + valAccessor(d); 
        });
    

作業フィドルを参照してください: http://jsfiddle.net/nrabinowitz/cQXNK/9/

これには、負の数を適切に処理できるという利点があります。私が知る限り、ゼロパディングでは不可能です。それは同じくらい速いようです。欠点は、数値列に新しいディメンションを作成する必要があることですが、私の場合は通常、いずれにしてもそれが必要です。

于 2013-01-11T20:21:12.850 に答える