Tengo aquí un conjunto de objetos.

var list = [
    {"id": 439, "name": "John"},
    {"id": 439, "name": "John"},
    {"id": 100, "name": "Kevin"},
    {"id": 120, "name": "Max"},
    {"id": 439, "name": "John"}
];

Necesito extraer de esta matriz, el objeto más frecuente y construir una nueva matriz ordenada por el nombre más popular.

Hasta ahora, he tratado de seguir la forma en que se hizo desde este tema: Underscore.js: ¿Encuentra el valor más frecuente en una matriz?

// Build temp list
temp_list = _(
    _.chain(
        _(list).pluck('id')
    )
    .countBy()
    .pairs()
    .value()
)
.sortBy(1)
.reverse();

// Build final list with most frequently occurring first
_.map(temp_list, function(current) {
    return _.findWhere(list, {
        'id': parseInt(current[0])
    });
});

¿Podría existir una manera de mejorar este código ordenando directamente la lista inicial sin la necesidad de crear una lista temporal?

4
Toucouleur 12 may. 2016 a las 15:15

3 respuestas

La mejor respuesta

Ya lo tienes: puedes llamar a map directamente desde la llamada reverse. Así es como lo hice:

var newlist = _.chain(list)
    .countBy(function (item) { return item.id; })
    .pairs()
    .sortBy(function (item) { return item[1]; })
    .reverse()
    .map(function (item) { return _.findWhere(list, { id: parseInt(item[0]) }); })
    .value();

La caida:

cadena : devuelve una versión empaquetada de la matriz, que le permite encadenar las funciones de subrayado.

countBy : devuelve un objeto donde las claves son cualquier valor devuelto por la devolución de llamada, y los valores son el número de veces que ocurrieron esas claves.

pares : convierte { key: 'value' } a ['key', 'value']

sortBy : devuelve una matriz ordenada por el valor devuelto por la devolución de llamada

reverse : invierte la matriz

map : devuelve una nueva matriz donde cada elemento se basa en el elemento de la matriz original en ese índice y lo que se haga con ese valor en la devolución de llamada. En este caso, estamos utilizando id (item[0]) para obtener el objeto de la lista original.

valor : desenvuelve el objeto encadenable y devuelve el valor "en bruto".

3
Andrew Burgess 12 may. 2016 a las 12:33

Puede usar reduce, para obtener un recuento de elementos, después de eso un sortBy

Algo como esto

var list = [
    {"id": 439, "name": "John"},
    {"id": 439, "name": "John"},
    {"id": 100, "name": "Kevin"},
    {"id": 120, "name": "Max"},
    {"id": 439, "name": "John"}
];

var finalList = _.chain(list)
	.reduce(function(memo, item){
	var previous = _.findWhere(memo,{id:item.id});
  if(previous){
  	previous.count++;
  }else{
  	item.count=1;
  	memo.push(item);
  }
  return memo;
},[])
	.sortBy('count')
  .reverse()
  .value();
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
0
AldoRomo88 12 may. 2016 a las 12:33
_.chain(list)
    .countBy("id").pairs().sortBy()
    .reverse().map(function (element) {return _.findWhere(list, { id: parseInt(element[0]) }); }).value()
var list = [
    {"id": 439, "name": "John"},
    {"id": 439, "name": "John"},
    {"id": 100, "name": "Kevin"},
    {"id": 120, "name": "Max"},
    {"id": 439, "name": "John"}
];
var result = _.chain(list)
    .countBy("id").pairs().sortBy()
    .reverse().map(function (element) {return _.findWhere(list, { id: parseInt(element[0]) }); }).value();
console.log(result);
document.write(JSON.stringify(result));
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
2
Vladu Ionut 12 may. 2016 a las 12:41