Compruebe si todos los valores de la matriz son iguales

190

Necesito encontrar matrices donde todos los valores sean iguales. ¿Cuál es la forma más rápida de hacer esto? ¿Debo recorrerlo y solo comparar valores?

['a', 'a', 'a', 'a'] // true
['a', 'a', 'b', 'a'] // false
Marvin3
fuente
1
@TJCrowder Apuesto a que ya estás pensando en la mejor solución;)
VisioN
2
@TJCrowder: Sin mencionar la disposición de los que preguntan a aceptar las respuestas. Los usuarios con 1 representante a menudo parecen ser tipos de preguntar y ejecutar que se van tan pronto como tienen una respuesta para copiar y pegar, últimamente.
Cerbrus
1
¿Algo en torno a este enfoque debería funcionar? a.join(',').split(a[0]).length === a.length + 1
Jashwant
1
@ TomášZato: "OP" significa "póster original" (la persona que hace la pregunta).
TJ Crowder

Respuestas:

290
const allEqual = arr => arr.every( v => v === arr[0] )
allEqual( [1,1,1,1] )  // true

O una línea:

[1,1,1,1].every( (val, i, arr) => val === arr[0] )   // true

Array.prototype.every (de MDN): el every()método prueba si todos los elementos de la matriz pasan la prueba implementada por la función proporcionada.

golopot
fuente
11
La brevedad es el alma del ingenio
svarog
1
He creado un caso jsperf . Este método supera a la mayoría de los candidatos.
Junliang Huang
1
const everythings_equal = array => array.every(thing => thing === array[0]);
Константин Ван
8
Utilizar someen lugar de every: arr.some( v => v !== arr[0] ). Esto volverá temprano cuando el primer elemento sea desigual arr[0].
Jan
2
@ Jan everyregresa temprano también.
golopot
111

Editar: Sé un ninja rojo:

!!array.reduce(function(a, b){ return (a === b) ? a : NaN; });

Resultados:

var array = ["a", "a", "a"] => result: "true"
var array = ["a", "b", "a"] => result: "false"
var array = ["false", ""] => result: "false"
var array = ["false", false] => result: "false"
var array = ["false", "false"] => result: "true"
var array = [NaN, NaN] => result: "false" 

Advertencia:

var array = [] => result: TypeError thrown

Esto se debe a que no pasamos un Valor inicial . Por lo tanto, es posible que desee verificar array.lengthprimero.

Martín
fuente
55
podría llegar un poco tarde a la fiesta ... ¡creo que esto no funciona si tu matriz está hecha de falses! por ejemplo, pruebe [false, false, false] .reduce (function (a, b) {return (a === b)? a: false;});
George Flourentzos
3
@ Martin: ["false", ""]regresa true: /
dalgard
66
Esto se puede tomar una muesca mediante el uso NaN. Dado que ambos NaN === NaNy NaN !== NaNson falsos, garantiza que una vez que prevse establece en NaN, ningún valor puede eliminarlo. Además, agregar una doble negación convierte los resultados en truey false, dado que NaNes falso. Forma final:!!array.reduce(function(a, b){ return (a === b) ? a : NaN; });
Filipe Silva
3
Downvoted . ¿Qué pasa si los elementos son iguales pero falsos ?
Константин Ван
3
Voté en contra porque esto no funciona con valores booleanos.
Tyguy7
62

Esto funciona. Puede crear un método en Array utilizando un prototipo.

if (Array.prototype.allValuesSame === undefined) {
  Array.prototype.allValuesSame = function() {
    for (let i = 1; i < this.length; i++) {
      if (this[i] !== this[0]) {
        return false;
      }
    }
    return true;
  }
}

Llama a esto de esta manera:

let a = ['a', 'a', 'a'];
let b = a.allValuesSame(); // true
a = ['a', 'b', 'a'];
b = a.allValuesSame();     // false
Robert Fricke
fuente
55
muy agradable, pero cuidado: IE no admite esta forma de asignar prototipos. Lo uso de todos modos.
Tomáš Zato - Restablece a Monica
55
@ TomášZato: IE admite el aumento de la Array.prototypemulta (incluso IE6). Solo los prototipos de elementos DOM son compatibles con algunas versiones anteriores de IE.
TJ Crowder
44
No creo que sea una buena idea ser mono parcheando prototipos incorporados. Si varias bibliotecas lo hacen, puede conducir a un comportamiento inesperado que es muy difícil de depurar.
Mark Wilbur
1
@MarkWilbur +1 especialmente si haces un bucle for..in en las siguientes matrices, entrarás allValuesSameen el bucle
Olivier Pons el
1
Seguí adelante y modernicé esto, sin alterar la intención.
Sr. Polywhirl
30

En JavaScript 1.6, puede usar Array.every:

function AllTheSame(array) {
    var first = array[0];
    return array.every(function(element) {
        return element === first;
    });
}

Probablemente necesite algunas comprobaciones de cordura, por ejemplo, cuando la matriz no tiene elementos. (Además, esto no funcionará cuando todos los elementos lo sean NaNdesde entonces NaN !== NaN, pero eso no debería ser un problema ... ¿verdad?)

Mattias Buelens
fuente
30

Puede convertir la matriz en un conjunto. Si el tamaño del conjunto es igual a 1, entonces todos los elementos de la matriz son iguales.

function allEqual(arr) {
  return new Set(arr).size == 1;
}

allEqual(['a', 'a', 'a', 'a']); // true
allEqual(['a', 'a', 'b', 'a']); // false
Huy Tran
fuente
Brillante. Solo tenga en cuenta que allEqual([NaN, NaN])da trueen este caso.
Константин Ван
12

Y para la comparación de rendimiento también hice un punto de referencia:

function allAreEqual(array){
    if(!array.length) return true;
    // I also made sure it works with [false, false] array
    return array.reduce(function(a, b){return (a === b)?a:(!b);}) === array[0];
}
function same(a) {
    if (!a.length) return true;
    return !a.filter(function (e) {
        return e !== a[0];
    }).length;
}

function allTheSame(array) {
    var first = array[0];
    return array.every(function(element) {
        return element === first;
    });
}

function useSome(array){
    return !array.some(function(value, index, array){
        return value !== array[0];
    });
}

Resultados:

allAreEqual x 47,565 ops/sec ±0.16% (100 runs sampled)
same x 42,529 ops/sec ±1.74% (92 runs sampled)
allTheSame x 66,437 ops/sec ±0.45% (102 runs sampled)
useSome x 70,102 ops/sec ±0.27% (100 runs sampled)

Entonces, aparentemente usar builtin array.some () es el método más rápido de los muestreados.

Martín
fuente
3
Es una buena idea comprobar qué es más eficaz aquí. La razón por la Array#someque a veces va a funcionar mejor es que una vez que la función de devolución de llamada devuelve verdadero, deja de iterar. Entonces, si todos los elementos son iguales, el rendimiento debería ser idéntico al Array#every. Y el rendimiento relativo cuando todos los elementos no son iguales variará según el índice del primer elemento que no coincida.
danmactough
3
Buena esa. Podrías haber nombrado a cada uno con la función utilizada lol. Por ejemplo: reducir, filtrar, todos, algunos
Z. Khullah
donde está el ciclo for nativo, apuesto a que supera a todos estos por un factor de 5
PirateApp
9

Respuesta más corta usando subrayado / lodash

function elementsEqual(arr) {
    return !_.without(arr, arr[0]).length
}

Especificaciones:

elementsEqual(null) // throws error
elementsEqual([]) // true
elementsEqual({}) // true
elementsEqual([1]) // true
elementsEqual([1,2]) // false
elementsEqual(NaN) // true

editar:

O incluso más corto, inspirado por la respuesta de Tom:

function elementsEqual2(arr) {
    return _.uniq(arr).length <= 1;
}

Especificaciones:

elementsEqual2(null) // true (beware, it's different than above)
elementsEqual2([]) // true
elementsEqual2({}) // true
elementsEqual2([1]) // true
elementsEqual2([1,2]) // false
elementsEqual2(NaN) // true
Joe promedio
fuente
6

Si ya está usando underscore.js , entonces aquí hay otra opción usando _.uniq:

function allEqual(arr) {
    return _.uniq(arr).length === 1;
}

_.uniqdevuelve una versión libre de duplicados de la matriz. Si todos los valores son iguales, entonces la longitud será 1.

Como se menciona en los comentarios, dado que puede esperar que regrese una matriz vacía true, también debe verificar ese caso:

function allEqual(arr) {
    return arr.length === 0 || _.uniq(arr).length === 1;
}
Tom Fenech
fuente
Pero si la matriz está vacía, su respuesta volverá false. Si bien creo que debería ser true. Sin .length <= 1embargo, cambiar a será suficiente.
promedio Joe
@ Kasztan ese es un punto justo. He actualizado mi respuesta para cubrir ese caso.
Tom Fenech
6

Sí, puede verificarlo también usando el filtro como se muestra a continuación, muy simple, verificando que todos los valores sean los mismos que el primero:

//ES6
function sameValues(arr) {
  return arr.filter((v,i,a)=>v===a[0]).length === arr.length;
} 

También se puede hacer usando todos los métodos de la matriz:

//ES6
function sameValues(arr) {
  return arr.every((v,i,a)=>v===a[0]);
} 

y puede verificar sus matrices como a continuación:

sameValues(['a', 'a', 'a', 'a']); // true
sameValues(['a', 'a', 'b', 'a']); // false

O puede agregarlo a las funcionalidades de matriz nativas en JavaScript si lo reutiliza mucho:

//ES6
Array.prototype.sameValues = Array.prototype.sameValues || function(){
 this.every((v,i,a)=>v===a[0]);
}

y puede verificar sus matrices como a continuación:

['a', 'a', 'a', 'a'].sameValues(); // true
['a', 'a', 'b', 'a'].sameValues(); // false
Alireza
fuente
5

Puede usar Array.everysi es compatible:

var equals = array.every(function(value, index, array){
    return value === array[0];
});

El enfoque alternativo de un bucle podría ser algo así como sort

var temp = array.slice(0).sort();
var equals = temp[0] === temp[temp.length - 1];

O, si los artículos son como la pregunta, algo sucio como:

var equals = array.join('').split(array[0]).join('').length === 0;

También funciona

ZER0
fuente
Tienes el primer ejemplo al revés. Debe ser equals = !array.some( (v,i,a) => v!==a[0] ). De lo contrario, solo verificará que cualquier valor sea igual al primero, lo que, por supuesto, siempre será cierto :)
Mark Kahn
No exactamente, lo usé en somelugar de everylo que mencioné en el primer párrafo. :) Gracias por la captura!
ZER0
5

Puede obtener este one-liner para hacer lo que quiera con las funciones de flecha Array.prototype.every , Object.is y ES6:

const all = arr => arr.every(x => Object.is(arr[0], x));
Noor
fuente
2
Por favor, describa la solución que está proponiendo.
il_raffa
3

Creo que la forma más sencilla de hacer esto es crear un ciclo para comparar cada valor con el siguiente. Mientras haya una ruptura en la "cadena", entonces devolverá falso. Si el primero es igual al segundo, el segundo igual al tercero y así sucesivamente, entonces podemos concluir que todos los elementos de la matriz son iguales entre sí.

dado un conjunto de datos [], puede usar:

for(x=0;x<data.length - 1;x++){
    if (data[x] != data[x+1]){
        isEqual = false;            
    }
}
alert("All elements are equal is " + isEqual);
Nicholas
fuente
3
arr.length && arr.reduce(function(a, b){return (a === b)?a:false;}) === arr[0];
Martín
fuente
3

Actualizar nueva solución: verificar índice

 let a = ['a', 'a', 'b', 'a'];
 let a = ['a', 'a', 'a', 'a'];
 let check = (list) => list.every(item => list.indexOf(item) === 0);
 check(a); // false;
 check(b); // true;

Actualizado con ES6: el uso list.everyes la forma más rápida:

 let a = ['a', 'a', 'b', 'a'];
 let check = (list) => list.every(item => item === list[0]);

versión antigua:

      var listTrue = ['a', 'a', 'a', 'a'];
      var listFalse = ['a', 'a', 'a', 'ab'];

      function areWeTheSame(list) { 
         var sample = list[0];
         return (list.every((item) => item === sample));
      }
Kai
fuente
2

Puedes usar esto:

function same(a) {
    if (!a.length) return true;
    return !a.filter(function (e) {
        return e !== a[0];
    }).length;
}

La función primero verifica si la matriz está vacía. Si es así, sus valores son iguales. De lo contrario, filtra la matriz y toma todos los elementos que son diferentes de la primera. Si no hay tales valores => la matriz contiene solo elementos iguales, de lo contrario no lo hace.

Minko Gechev
fuente
1

La _.isEqual(object, other)función de subrayado parece funcionar bien para las matrices. El orden de los elementos en la matriz importa cuando verifica la igualdad. Ver http://underscorejs.org/#isEqual .

Jon Onstott
fuente
1
var listTrue = ['a', 'a', 'a', 'a'];
var listFalse = ['a', 'a', 'a', 'ab'];

function areWeTheSame(list) { 
    var sample = list[0];
    return !(list.some(function(item) {
        return !(item == sample);
    }));
}
usuario4861889
fuente
También explique lo que hizo en lugar de simplemente pegar un código.
Wouter J
1

Es sencillo. Crea una función y pasa un parámetro. En esa función, copie el primer índice en una nueva variable. Luego, crea un bucle for y recorre la matriz. Dentro de un ciclo, cree un ciclo while con una condición que verifique si la nueva variable creada es igual a todos los elementos en el ciclo. si su retorno igual es verdadero después de que el ciclo for se complete, de lo contrario, devuelve falso dentro del ciclo while.

function isUniform(arra){
    var k=arra[0];
    for (var i = 0; i < arra.length; i++) {
        while(k!==arra[i]){
            return false;
        }
    }
    return true;
}
Adithya Santhosh
fuente
1

La respuesta aceptada funcionó muy bien, pero quería agregar un poco. No funcionó para mí ===porque estaba comparando matrices de matrices de objetos, sin embargo, a lo largo de mi aplicación, he estado usando el paquete fast-deep-equal que recomiendo encarecidamente. Con eso, mi código se ve así:

let areAllEqual = arrs.every((val, i, arr) => equal(val, arr[0]) );

y mis datos se ven así:

[  
  [
    {
      "ID": 28,
      "AuthorID": 121,
      "VisitTypeID": 2
    },
    {
      "ID": 115,
      "AuthorID": 121,
      "VisitTypeID": 1
    },
    {
      "ID": 121,
      "AuthorID": 121,
      "VisitTypeID": 1
    }
  ],
  [
    {
      "ID": 121,
      "AuthorID": 121,
      "VisitTypeID": 1
    }
  ],
  [
    {
      "ID": 5,
      "AuthorID": 121,
      "VisitTypeID": 1
    },
    {
      "ID": 121,
      "AuthorID": 121,
      "VisitTypeID": 1
    }
  ]
]
Michael Aaron Wilson
fuente
1
  1. Crea una cadena uniendo la matriz.
  2. Crea una cadena repitiendo el primer carácter de la matriz dada
  3. unir ambas cuerdas

	function checkArray(array){
		return array.join("") == array[0].repeat(array.length);	
	}

	console.log('array: [a,a,a,a]: ' + checkArray(['a', 'a', 'a', 'a']));
	console.log('array: [a,a,b,a]: ' + checkArray(['a', 'a', 'b', 'a']));

¡Y estás HECHO!

Rahul Vala
fuente
1

Ahora puede utilizar conjuntos para hacerlo fácilmente.

let a= ['a', 'a', 'a', 'a']; // true
let b =['a', 'a', 'b', 'a'];// false

console.log(new Set(a).size === 1);
console.log(new Set(b).size === 1);

Krishnadas PC
fuente
1

Podrías usar un bucle for:

function isEqual(arr) {
  var first = arr[0];
  for (let i = 1; i < arr.length; i++) {
    if (first !== arr[i]) {
      return false;
    }
  }
  return true;
}
Armando Guarino
fuente
0

Bueno, esto realmente no es muy complicado. Tengo una fuerte sospecha de que ni siquiera lo intentaste. Lo que debe hacer es elegir el primer valor, guardarlo en la variable y luego, dentro de un forciclo, comparar todos los valores posteriores con el primero.
Intencionalmente no compartí ningún código. Encuentre cómo forse usa y cómo se comparan las variables.

Tomáš Zato - Restablece a Monica
fuente
8
No me gusta esta respuesta. No le permitiría saber si el segundo valor era el mismo que el tercero, etc. Obviamente, el bucle anidado lo haría, pero eso es conceptualmente diferente a un scripter novato.
jtromans
3
@jtromans: debido a la propiedad transitiva de la igualdad, si A == B y A == C entonces sabemos B == C; no tiene que verificarlo "manualmente" con un bucle anidado, etc. La repetición de la comparación con un solo valor (primer valor en la matriz, no uno arbitrario :) es exactamente lo que sugiere esta respuesta y también la respuesta aceptada.
OV
@ov De hecho, en mi apuro leí mal la pregunta, que pensé que en ese momento requería más que simplemente verificar que todos los valores son iguales (! duh).
jtromans
9
No es complicado Y tampoco lo son las otras respuestas en la página. Pero para mí, esta respuesta es, con mucho, la menos útil.
Charlie
1
Originalmente estaba destinado a hacer un punto fuerte hacia el OP insistiendo en que intenta pensar antes de hacer preguntas.
Tomáš Zato - Restablece a Mónica el
0

Solución simple de una línea, simplemente compárela con una matriz llena con la primera entrada.

if(arr.join('') === Array(arr.length).fill(arr[0]).join(''))
Pyviet
fuente
Esa no parece ser una solución que pueda usarse en cualquier lugar
Lu4
Está bastante cerca de bien. Mejor sería algo así como: function arrayOfSame (arr) {return (arr.join ('') == (new Array (arr.length + 1) .join (arr [0]))); }
Arkain
0

Otra forma interesante cuando utiliza la sintaxis de la función de flecha ES6:

x = ['a', 'a', 'a', 'a']
!x.filter(e=>e!==x[0])[0]  // true

x = ['a', 'a', 'b', 'a']
!x.filter(e=>e!==x[0])[0] // false

x = []
!x.filter(e=>e!==x[0])[0]  // true

Y cuando no desee reutilizar la variable para array (x):

!['a', 'a', 'a', 'a'].filter((e,i,a)=>e!==a[0])[0]    // true

Cartel anterior de la OMI que usaba array.every (...) tiene la solución más limpia.

Tomasz Szawara
fuente
0
function isUniform(array) {   
  for (var i=1; i< array.length; i++) {
    if (array[i] !== array[0]) { return false; }
  }

  for (var i=1; i< array.length; i++) {
    if (array[i] === array[0]) { return true; }
  }
}
  • Para el primer bucle; cada vez que detecta desigual, devuelve "falso"
  • Se ejecuta el primer bucle, y si devuelve falso, tenemos "falso"
  • Cuando no se devuelve falso, significa que será verdadero, por lo que hacemos el segundo bucle. Y, por supuesto, tendremos "verdadero" desde el segundo bucle (porque el primer bucle encontró que NO es falso)
Jaden Tran
fuente
0

esto podría funcionar, también puede usar el código de comentario que también funciona bien con el escenario dado.

function isUniform(){
	var arrayToMatch = [1,1,1,1,1];
	var temp = arrayToMatch[0];
	console.log(temp);
  /* return arrayToMatch.every(function(check){
    return check == temp;
   });*/
var bool;
   arrayToMatch.forEach(function(check){
    bool=(check == temp);
   })
  console.log(bool);
}
isUniform();

Aman Pathak
fuente
0

Otra forma con tamaño delimitado y lista organizada:

matriz1 = [1,2,3]; matriz2 = [1,2,3];

function isEqual(){

    return array1.toString()==array2.toString();
}
Fábio Balbino
fuente
0

Puede convertir la matriz en un conjunto y verificar su tamaño

En el caso de entradas de matriz primitivos, es decir number, string:

const isArrayWithEqualEntries = array => new Set(array).size === 1

En el caso de una matriz de objetos con algún campo para probar la equivalencia, diga id:

const mapper = ({id}) => id
const isArrayWithEqualEntries = array => new Set(array.map(mapper)).size === 1
Simón
fuente
-4

En PHP, hay una solución muy simple, un método de una línea:

(count (array_count_values ​​($ array)) == 1)

Por ejemplo :

$arr1 = ['a', 'a', 'a', 'a'];
$arr2 = ['a', 'a', 'b', 'a'];


print (count(array_count_values($arr1)) == 1 ? "identical" : "not identical"); // identical
print (count(array_count_values($arr2)) == 1 ? "identical" : "not identical"); // not identical

Eso es todo.

alemán
fuente