Dada esta matriz:

[1, 1, 2, 1, 1, 1, 2, 3, 4, 4, 4, 6, 4, 4]

¿Cómo puedo contar eficientemente los mismos elementos más cercanos en la matriz? El resultado que esperaría es:

1 => 2,
2 => 1,
1 => 3,
2 => 1,
3 => 1,
4 => 3,
6 => 1,
4 => 2

No sé cómo formular correctamente la pregunta, pero creo que el ejemplo es bastante claro.

Intenté usar reducir para hacer más compacto y elegante, pero siempre obtengo un valor con el número total del mismo valor en la matriz.

let result = testArray.reduce((allValues, value) => {
      if(value in allValues){
        allValues[value]++;
      } else {
        allValues[value] = 1;
      }

      return allValues;
    }, {});
2
user7383359 11 ene. 2017 a las 14:25

4 respuestas

La mejor respuesta

Puede verificar el último elemento y, si es igual, aumentar el recuento, si no, empujar un nuevo objeto al conjunto de resultados.

var array = [1, 1, 2, 1, 1, 1, 2, 3, 4, 4, 4, 6, 4, 4],
    count = array.reduce((r, a, i, aa) => {
        if (aa[i - 1] === a) {
            r[r.length - 1].count++;
        } else {
            r.push({ value: a, count: 1 });
        }
        return r;
    }, []);

console.log(count);
.as-console-wrapper { max-height: 100% !important; top: 0; }
1
Nina Scholz 11 ene. 2017 a las 11:37

Mientras que Array.prototype.reduce es una buena función, tiene algunos problemas de compatibilidad.

Aquí hay una solución usando old school para bucles:

var arr = [1, 1, 2, 1, 1, 1, 2, 3, 4, 4, 4, 6, 4, 4];
var results = [];
for (var indexA = 0; indexA < arr.length; indexA++) {
    var a = arr[indexA];
    if (results.length > 0) {
        if (a == results[results.length - 1]["value"]) {
            continue;
        }
    }
    var r = { value: a, index: indexA, count: 0 };
    for (var indexB = indexA; indexB < arr.length; indexB++) {
        var b = arr[indexB];
        if (a != b) {
            break;
        }
        r.count++;
    }
    results.push(r);
}
console.log(results);
0
Emil S. Jørgensen 11 ene. 2017 a las 11:45

Otra solución que utiliza Array.prototype.reduce y un hash table - vea la demostración a continuación:

var array = [1, 1, 2, 1, 1, 1, 2, 3, 4, 4, 4, 6, 4, 4];

var result = array.reduce(function(hash){
  return function(p,c,i){
    hash[c] = (hash[c] || 0) + 1;
    if(hash.prev && (hash.prev !== c || i == array.length - 1)) {
      let obj= {}; 
      obj[hash.prev] = hash[hash.prev];
      delete hash[hash.prev];
      p.push(obj);
    }
    hash.prev = c;
    return p;
  }
}(Object.create(null)),[]);

console.log(result);
.as-console-wrapper{top:0;max-height:100%!important;}
0
kukkuz 11 ene. 2017 a las 11:42

Las soluciones publicadas están bien, pero como señaló @Emil S. Jørgensen, puede haber problemas de compatibilidad al usar Array.reduce. Además, la solución de la vieja escuela sugerida por @Emil S. Jørgensen usa dos bucles. Si desea tener una solución un poco más eficiente, simple y directa que funcione en todos los navegadores, utilice:

var arr = [1, 1, 2, 1, 1, 1, 2, 3, 4, 4, 4, 6, 4, 4];
var result = [];

var current = arr[0];
var count = 1;

for (var i = 1; i <= arr.length; i++)
{
    if(arr[i] === current)
    {
        count+= 1;
    }
    else
    {
        var newObj = {};
        newObj[current] = count;
        result.push(newObj);
        current = arr[i];
        count = 1;
    }
}

console.log(result); //prints the solution
0
george 11 ene. 2017 a las 12:14