en ES2015, Javascript, Programación Funcional

Cómo ordenar un array de strings según unas prioridades específicas

El otro día en un proyecto me surgió la necesidad de dejar preparado un código para que dado un array de strings, éste quedara ordenado en base a unas prioridades especificas.

Por ejemplo, dado un array de tipos de media (obtenido por ejemplo a través de una consulta a una API), me interesa que los tipo «foto» queden siempre al principio del array,  luego los tipo «audio», etc…

/* criteria: "foto","mapa","audio","video","interactivo" */
fnOrderMedia = makeFnSortArray("foto","audio","mapa","video","interactivo");

["audio", "mapa", "foto"].sort(fnOrderMedia)
// ["foto","audio","mapa"]

Otro caso típico es el de ordenar paises para un dropdown, donde por ejemplo puedo querer que determinados paises aparezcan siempre primero (por ejemplo «Spain», «France», «Italy») y todo lo que no esté en mi lista de «primeros» quede ordenado alfabeticamente

/* criteria: "spain","portugal","france" */
fnOrderCountries = makeFnSortArray("spain","portugal","france");

["germany", "france", "italy", "spain", "england"].sort(fnOrderCountries)
// ["spain","france","england","germany","italy"]

Al final, generalizando, me interesa poder ordenar un array de strings en base a un criterio personalizado y todo lo que no esté en ese criterio quede ordenado alfabeticamente.

Para esto me monté una función factory creadora de funciones «que ordenan en base a un array de prioridades» lista para pasársela como callback al método sort del prototype de array.

Aqui teneis el código en ES2015 de esta función factory y de su aplicación:

const makeFnSortArray = ( ...criteria ) => {

  const order = criteria.reduce( ( o, item, i) => {
    o[item] = ++i; 
    return o;
  }, {})
  
  return (a, b) => {
    if ( (order[b] && !order[a]) || order[a] > order[b] ) return 1;
    if ( (order[a] && !order[b]) || (order[a] < order[b]) ) return -1;
    if ( a > b ) return 1;
    if ( a < b ) return -1;
    return 0;
  }
}
 
 
const fnOrderMedia = makeFnSortArray("foto","mapa","audio");
 
["audio", "foto", "interactivo", "mapa", "video"].sort(fnOrderMedia) 
// ["foto","mapa","audio","interactivo","video"]

Y aqui teneis el código en ES5:

"use strict";

var makeFnSortArray = function makeFnSortArray() {
  for (var _len = arguments.length, criteria = Array(_len), _key = 0; _key < _len; _key++) {
    criteria[_key] = arguments[_key];
  }

  var order = criteria.reduce(function (o, item, i) {
    o[item] = ++i;
    return o;
  }, {});

  return function (a, b) {
    if (order[b] && !order[a] || order[a] > order[b]) return 1;
    if (order[a] && !order[b] || order[a] < order[b]) return -1;
    if (a > b) return 1;
    if (a < b) return -1;
    return 0;
  };
};

var fnOrderMedia = makeFnSortArray("foto", "mapa", "audio");

["audio", "foto", "interactivo", "mapa", "video"].sort(fnOrderMedia);
// ["foto","mapa","audio","interactivo","video"]

Y aqui podeis verlo en funcionamiento con unos cuantos tests:

[advanced_iframe src=»//jsfiddle.net/juanma/4ckaq2y6/embedded/result,js/» width=»100%» height=»400″]

Post Anterior
Post Siguiente

Política de Comentarios de pixelovers

Responsable » Juan Manuel Garrido
Finalidad » Moderación de los comentarios
Legitimación » Tu consentimiento expreso que te será requerido por Disqus.
Destinatarios » Los datos de tus comentarios los guardará Disqus, mi sistema de comentarios, que está acogido al acuerdo de seguridad EU-US Privacy Shield tal y como recoge su politica de privacidad
Derechos » Desde Disqus, por tanto, podrás acceder, rectificar, limitar y suprimir tus comentarios o tu cuenta
Tienes más detalles acerca del tratamiento de los datos relacionados con los comentarios en nuestra (Política de Privacidad)