web-dev-qa-db-ja.com

backbone.jsを使用して文字列を逆順にソートする

Backbone.jsコレクションを逆順に並べ替えようとしています。これを整数で行う方法についての以前の回答はありますが、文字列での回答はありません。

var Chapter  = Backbone.Model;
var chapters = new Backbone.Collection;

chapters.comparator = function(chapter) {
  return chapter.get("title");
};

chapters.add(new Chapter({page: 9, title: "The End"}));
chapters.add(new Chapter({page: 5, title: "The Middle"}));
chapters.add(new Chapter({page: 1, title: "The Beginning"}));

alert(chapters.pluck('title'));

上記のコードは、章をソートしますfrom A-> Zですが、それをソートするコンパレータをどのように記述すればよいですかfrom Z-> A

40
Emil Stenström

使用できるコンパレーター関数には2つのバージョンがあります。sortByバージョン-1つのパラメーターを使用する例に示されているバージョン、またはsort- documentation が言う、より標準的なソート関数を返すことができます:

"sortBy"コンパレーター関数はモデルを取り、数値または文字列値を返します。これにより、他のモデルと相対的にモデルを順序付ける必要があります。 「ソート」コンパレーター関数は2つのモデルを取り、最初のモデルが2番目のモデルの前に来る場合は-1、同じランクの場合は0、最初のモデルが後に来る場合は1を返します。

したがって、この場合、別のコンパレーター関数を作成できます。

var Chapter  = Backbone.Model;
var chapters = new Backbone.Collection;

chapters.comparator = function(chapterA, chapterB) {
  if (chapterA.get('title') > chapterB.get('title')) return -1; // before
  if (chapterB.get('title') > chapterA.get('title')) return 1; // after
  return 0; // equal
};

chapters.add(new Chapter({page: 9, title: "The End"}));
chapters.add(new Chapter({page: 5, title: "The Middle"}));
chapters.add(new Chapter({page: 1, title: "The Beginning"}));

alert(chapters.pluck('title'));

したがって、応答として取得する必要があります。

"The Middle", "The End", "The Beginning"
20
Dan Smart

あなたは出来る:

  • 文字列の各文字の文字コードを取得し、
  • _0xffff_(_string.charCodeAt_の最大戻り値)から各値を減算します。
  • _String.fromCharCode_を使用して、それを「否定された」文字の文字列に戻します。

そしてそれがあなたのソートキーになります。

_chapters.comparator = function(chapter) {
    return String.fromCharCode.apply(String,
        _.map(chapter.get("title").split(""), function (c) {
            return 0xffff - c.charCodeAt();
        })
    );
}
_

そして出来上がり:

_> console.log(chapters.pluck('title'));
["The Middle", "The End", "The Beginning"]
_

注:比較文字列が長い場合(65 kb以上など)、問題が発生する可能性があります(以下のMattのコメントを参照)。これを回避し、比較を少し高速化するには、比較文字列の短いスライスを使用します。 (上記の例では、代わりにchapter.get("title").slice(0, 100).split("")を使用できます。)必要なスライスの長さは、アプリケーションによって異なります。

45

数値以外の値を使用している場合、逆の並べ替えを行う明確な方法はありません。バックボーンは、アンダースコアの_.sortBy()および_.sortedIndex()メソッドを使用して、コンパレーターに基づいてモデルを並べ替えます。これらのメソッドは、自動的に昇順に並べ替えます。 pluckの結果は配列になるため、これを行う素朴な方法はchapters.pluck('title').reverse()を使用することです。ただし、一部のコレクションメソッドでreverseを呼び出すと、所定の場所にあるコレクションモデルが逆転するため、次に呼び出すと、モデルは昇順で戻ります。あなたはいつも次のようなことをすることができます:

var results = [],
    titles  = chapters.pluck('title');

for(var i=0, len=titles.length; i<len; i++) {
  results.Push(titles[i]);
}

results.reverse();

これは、バックボーンコレクションのモデル配列には影響しません。メモリに完全に新しい結果配列を作成しますが、元のモデルへの参照は保持するため、saveなどを呼び出すと、コレクションの状態が更新されます。

しかし、それはあまりエレガントではなく、結果を元に戻したいときはいつでも、プロジェクト全体に多くの追加のコーディングが作成されます。私たちはもっとうまくできると思います。

これを機能させるには、コンパレーターメソッドで扱いにくいJavaScriptニンジャリーを少し実行して、機能させる必要があります。これはテストされていないことに注意してください。

chapters.comparator = function(chapter) {
  var alphabet = '0123456789abcdefghijklmnopqrstuvwxyz',
      title = chapter.get('title').toLowerCase(),
      inverse_title = '',
      index;

  for(var i=0, len=title.length; i<len; i++) {
    index = alphabet.indexOf(title.charAt(i));

    if(index === -1) {
      inverse_title += title.charAt(i);
      continue;
    }

    inverse_title += alphabet.charAt(alphabet.length - index - 1);
  }

  return inverse_title;
};

この概念はおそらくシンボルなどを考慮するために改善する必要がありますが、本質的には「Z」が「0」、「Y」が「1」になるようにコンパレーター文字列を反転します。あなたが後をソートします。

12
Gary Chambers

バックボーンは単に.sortByメソッドを使用するだけなので、独自のロジックでプロキシするだけです。

collectionInQuestion.sortBy = function () {
  var models = _.sortBy(this.models, this.comparator);
  if (forSomeReason) {
    models.reverse();
  }
  return models;
};

..または別の場所に追加します。

TweakedCollection = Backbone.Collection.extend({ sortBy: [...] })
12

私はテーブルの並べ替えで同様の問題を解決しましたが、これらの答えであまり助けが見つからなかったため、コードを共有したいと思いました。

events: {

    'click th.sortable': function(e) {
        var $this = $(e.target),
            order = $this.hasClass('asc') ? 'desc' : 'asc',
            field = $this.data('field'); /* this is a string */

        $this.siblings().addBack().removeClass('asc desc');
        $this.addClass( order );

        this.bodyView.collection.comparator = field;
        this.bodyView.collection.sort();
        if ( order === 'desc' ) this.bodyView.collection.models.reverse();

        this.bodyView.render();
    }

},

この場合、関数の代わりにコンパレータを文字列に設定するだけです。文字列は、並べ替えに使用するプロパティの名前である必要があります。次に、順序を逆にする必要がある場合は、モデルでreverseを呼び出します。

0
David Fregoli