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
fuente
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
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.
const everythings_equal = array => array.every(thing => thing === array[0]);
some
en lugar de every
: arr.some( v => v !== arr[0] )
. Esto volverá temprano cuando el primer elemento sea desigual arr[0]
.
every
regresa temprano también.
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.length
primero.
false
s! por ejemplo, pruebe [false, false, false] .reduce (function (a, b) {return (a === b)? a: false;});
["false", ""]
regresa true
: /
NaN
. Dado que ambos NaN === NaN
y NaN !== NaN
son falsos, garantiza que una vez que prev
se establece en NaN, ningún valor puede eliminarlo. Además, agregar una doble negación convierte los resultados en true
y false
, dado que NaN
es falso. Forma final:!!array.reduce(function(a, b){ return (a === b) ? a : NaN; });
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
Array.prototype
multa (incluso IE6). Solo los prototipos de elementos DOM son compatibles con algunas versiones anteriores de IE.
allValuesSame
en el bucle
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 NaN
desde entonces NaN !== NaN
, pero eso no debería ser un problema ... ¿verdad?)
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
allEqual([NaN, NaN])
da true
en este caso.
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.
Array#some
que 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.
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
Si ya está usando underscore.js , entonces aquí hay otra opción usando _.uniq
:
function allEqual(arr) {
return _.uniq(arr).length === 1;
}
_.uniq
devuelve 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;
}
false
. Si bien creo que debería ser true
. Sin .length <= 1
embargo, cambiar a será suficiente.
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
Puede usar Array.every
si 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
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 :)
some
lugar de every
lo que mencioné en el primer párrafo. :) Gracias por la captura!
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));
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);
arr.length && arr.reduce(function(a, b){return (a === b)?a:false;}) === arr[0];
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.every
es 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));
}
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.
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 .
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);
}));
}
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;
}
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
}
]
]
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!
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);
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;
}
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 for
ciclo, comparar todos los valores posteriores con el primero.
Intencionalmente no compartí ningún código. Encuentre cómo for
se usa y cómo se comparan las variables.
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(''))
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.
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; }
}
}
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();
Otra forma con tamaño delimitado y lista organizada:
matriz1 = [1,2,3]; matriz2 = [1,2,3];
function isEqual(){
return array1.toString()==array2.toString();
}
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
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.
a.join(',').split(a[0]).length === a.length + 1