javascript sorting backbone.js underscore.js

javascript - Ordenando cadenas en orden inverso con backbone.js



sorting underscore.js (6)

Estoy tratando de ordenar una colección de Backbone.js en orden inverso. Hay respuestas anteriores sobre cómo hacer esto con enteros, pero ninguno con cadenas.

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''));

El código anterior ordena los capítulos de A -> Z , pero ¿cómo escribo un comparador que lo ordena desde Z -> A ?


Acabo de resolver un problema similar con la clasificación de tablas y quería compartir el código ya que no encontré mucha ayuda en estas respuestas:

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(); } },

en este caso, simplemente configuro el comparador en una cadena en lugar de una función; la cadena debe ser el nombre de la propiedad que desea ordenar. Luego solo llamo a la inversa en los modelos si el orden tiene que ser inverso.


Como Backbone simplemente usa el método .sortBy, simplemente proxy en tu propia lógica:

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

..o agregarlo en otro lugar ..

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


Hay dos versiones de la función de comparador que puede usar, ya sea la versión de sortBy , que se mostró en el ejemplo, que toma un parámetro u ordena , que puede devolver una función de clasificación más estándar, que la documentcloud.github.com/backbone/#Collection-comparator dice:

Las funciones del comparador "sortBy" toman un modelo y devuelven un valor numérico o de cadena mediante el cual el modelo debe ordenarse en relación con los demás. las funciones del comparador "ordenar" toman dos modelos, y devuelven -1 si el primer modelo debe venir antes del segundo, 0 si son del mismo rango y 1 si el primer modelo debe venir después.

Entonces, en este caso, podemos escribir una función de comparación diferente:

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''));

Entonces deberías obtener una respuesta:

"The Middle", "The End", "The Beginning"


Si está trabajando con valores no numéricos, no hay una forma obvia de hacer una ordenación inversa. Backbone utiliza los _.sortBy() y _.sortedIndex() de Subrayar para ordenar los modelos basados ​​en el comparador, y estos métodos se ordenan automáticamente en orden ascendente. La forma ingenua de hacer esto sería usar chapters.pluck(''title'').reverse() , ya que el resultado de pluck será una matriz. Pero al llamar al reverse en algunos métodos de Colección invertirá los modelos de Colección en su lugar, por lo que la próxima vez que lo llame, los modelos volverán a estar en orden ascendente. Siempre puedes hacer algo como:

var results = [], titles = chapters.pluck(''title''); for(var i=0, len=titles.length; i<len; i++) { results.push(titles[i]); } results.reverse();

Esto no afectaría a la matriz de modelos en su colección Backbone, ya que crearía una matriz de resultados completamente nueva en la memoria, pero conservaría referencias a los modelos originales, por lo que llamar a cosas como save aún actualizaría el estado de la Colección.

Pero eso no es muy elegante, y crea una gran cantidad de codificación adicional en todo el proyecto cada vez que quiera revertir los resultados. Pienso que podemos hacerlo mejor.

Para que esto funcione, deberá realizar un poco de ninjary de JavaScript poco manejable en su método de comparación para que esto funcione; tenga en cuenta que esto no se ha probado:

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; };

Este concepto probablemente necesite mejorarse para tener en cuenta los símbolos, etc., pero esencialmente invierte la cadena del comparador de tal manera que "Z" se convierte en "0", "Y" se convierte en "1", etc., lo que debería producir el reverso ordenar lo que buscas


Solo agrega menos antes del chapter.get

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


Tú podrías:

  • agarra el código de char para cada personaje en la cadena,
  • restar cada valor de 0xffff (el valor de retorno máximo de string.charCodeAt ),
  • use String.fromCharCode para convertir eso en una cadena de caracteres "negados"

y esa será tu clave de clasificación.

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

Y voilá:

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

Nota: si las cadenas de comparación son largas (como en 65 kb o más), puede tener problemas (consulte el comentario de Matt a continuación). Para evitar esto, y acelerar las comparaciones un poco, solo use una porción más corta de su cadena de comparación. (En el ejemplo anterior, puede ir por chapter.get("title").slice(0, 100).split("") lugar). El tiempo que necesite dependerá de su aplicación.