Verifique se todos os valores da matriz são iguais

190

Eu preciso encontrar matrizes onde todos os valores são iguais. Qual é a maneira mais rápida de fazer isso? Devo percorrê-lo e apenas comparar valores?

['a', 'a', 'a', 'a'] // true
['a', 'a', 'b', 'a'] // false
Marvin3
fonte
1
@TJCrowder Aposto que você já está pensando na melhor solução;)
VisioN
2
@TJCrowder: Sem mencionar a disposição dos solicitantes de realmente aceitarem respostas. Usuários com 1 representante geralmente parecem solicitar e executar tipos que saem assim que têm uma resposta capaz de copiar e colar recentemente.
Cerbrus
1
Algo em torno dessa abordagem deve funcionar? a.join(',').split(a[0]).length === a.length + 1
Jashwant
1
@ TomášZato: "OP" significa "pôster original" (a pessoa que faz a pergunta).
TJ Crowder
2
Possível duplicado de Verifique se cada item em uma matriz é idêntico em javascript
Anderson Verde

Respostas:

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

Ou uma linha:

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

Array.prototype.every (from MDN): O every()método testa se todos os elementos da matriz são aprovados no teste implementado pela função fornecida.

golopot
fonte
11
A brevidade é a alma da sagacidade
svarog
1
Eu criei um caso jsperf . Este método supera a maioria dos candidatos.
Junliang Huang
1
const everythings_equal = array => array.every(thing => thing === array[0]);
precisa saber é o seguinte
8
Use someem vez de every: arr.some( v => v !== arr[0] ). Isso retornará logo que o primeiro elemento for considerado desigual arr[0].
Jan
2
@ Jan everytambém retorna cedo.
golopot
111

Edit: Seja um ninja vermelho:

!!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" 

Aviso:

var array = [] => result: TypeError thrown

Isso ocorre porque não passamos um valor inicial . Portanto, você pode verificar array.lengthprimeiro.

Martin
fonte
5
pode ser um pouco tarde para a festa ... eu acho que isso não funciona se sua matriz é feita de falses! por exemplo, tente [false, false, false] .reduce (function (a, b) {return (a === b)? a: false;});
George Flourentzos
3
@Martin: ["false", ""]retorna true: /
dalgard 15/10
6
Isso pode ser aumentado usando NaN. Como ambos NaN === NaNe NaN !== NaNsão falsos, garante que, uma vez prevdefinido como NaN, nenhum valor possa removê-lo. A adição de uma dupla negação também converte os resultados em truee false, uma vez que NaNé falso. Forma final:!!array.reduce(function(a, b){ return (a === b) ? a : NaN; });
Filipe Silva
3
DOWNVOTED . E se os elementos forem iguais, mas falsos ?
precisa saber é o seguinte
3
Fiz voto negativo porque isso não funciona com valores booleanos.
precisa saber é o seguinte
62

Isso funciona. Você cria um método na matriz usando o protótipo.

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;
  }
}

Chame assim:

let a = ['a', 'a', 'a'];
let b = a.allValuesSame(); // true
a = ['a', 'b', 'a'];
b = a.allValuesSame();     // false
Robert Fricke
fonte
5
muito bom, mas cuidado: o IE não suporta essa maneira de atribuir protótipos. Eu uso assim mesmo.
Tomáš Zato - Restabelece Monica
5
@ TomášZato: O IE suporta o aumento da Array.prototypemulta (até o IE6). São apenas os protótipos de elementos DOM que algumas versões mais antigas do IE não oferecem suporte ao aumento.
TJ Crowder
4
Eu não acho que seja uma boa ideia estar usando os protótipos embutidos nos macacos. Se várias bibliotecas o fizerem, isso pode levar a um comportamento inesperado, que é muito difícil de depurar.
Mark Wilbur
1
@MarkWilbur +1 especialmente se você faz um loop for..in sobre os próximos matrizes, você vai ter allValuesSameno loop
Olivier Pons
1
Fui em frente e modernizei isso, sem alterar a intenção.
Sr. Polywhirl
30

No JavaScript 1.6, você pode usar Array.every:

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

Você provavelmente precisará de algumas verificações de integridade, por exemplo, quando o array não possui elementos. (Além disso, isso não funcionará quando todos os elementos forem NaNdesde então NaN !== NaN, mas isso não deve ser um problema ... certo?)

Mattias Buelens
fonte
30

Você pode transformar a matriz em um conjunto. Se o tamanho do conjunto for igual a 1, todos os elementos da matriz serão iguais.

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

allEqual(['a', 'a', 'a', 'a']); // true
allEqual(['a', 'a', 'b', 'a']); // false
Huy Tran
fonte
Brilhante. Basta notar que allEqual([NaN, NaN])trueneste caso.
precisa saber é o seguinte
12

E para comparação de desempenho, também fiz uma referência:

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)

Então, aparentemente, o uso do array.some () interno é o método mais rápido dos exemplos.

Martin
fonte
3
Boa idéia para verificar o que tem mais desempenho aqui. O motivo pelo qual o Array#somedesempenho às vezes é superior é que, quando a função de retorno de chamada retorna verdadeira, ela pára de iterar. Portanto, se todos os elementos forem de fato iguais, o desempenho deverá ser idêntico a Array#every. E o desempenho relativo quando todos os elementos não forem iguais variará com base no índice do primeiro elemento não correspondente.
danmactough
3
Agradável. Você poderia ter nomeado cada um com a função usada lol. Por exemplo: reduzir, filtro, cada, alguns
Z. Khullah
onde é o nativo para loop, eu aposto que supera tudo isso por um fator de 5
PirateApp
9

Resposta mais curta usando sublinhado / lodash

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

especificação:

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

editar:

Ou ainda mais, inspirado na resposta de Tom:

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

especificação:

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

Se você já está usando underscore.js , aqui está outra opção usando _.uniq:

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

_.uniqretorna uma versão sem duplicado da matriz. Se todos os valores forem iguais, o comprimento será 1.

Conforme mencionado nos comentários, como você pode esperar que uma matriz vazia retorne true, verifique também o caso:

function allEqual(arr) {
    return arr.length === 0 || _.uniq(arr).length === 1;
}
Tom Fenech
fonte
Mas se a matriz estiver vazia, sua resposta retornará false. Enquanto eu acho que deveria ser true. Mudar para .length <= 1deve ser o suficiente.
média Joe
@ Kasztan esse é um ponto justo. Atualizei minha resposta para cobrir esse caso.
precisa
6

Sim, você também pode verificá-lo usando o filtro abaixo, muito simples, verificando todos os valores iguais aos do primeiro:

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

Também pode ser feito usando todos os métodos na matriz:

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

e você pode verificar suas matrizes como abaixo:

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

Ou você pode adicioná-lo às funcionalidades nativas de Array em JavaScript, se você o reutilizar muito:

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

e você pode verificar suas matrizes como abaixo:

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

Você pode usar Array.everyse suportado:

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

A abordagem alternativa de um loop pode ser algo como sort

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

Ou, se os itens forem como a pergunta, algo sujo como:

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

Também funciona.

ZER0
fonte
Você tem o primeiro exemplo ao contrário. Deveria ser equals = !array.some( (v,i,a) => v!==a[0] ). Caso contrário, você está apenas verificando que qualquer valor é igual ao primeiro que irá, naturalmente, ser sempre verdade :)
Mark Kahn
Não exatamente, usei em somevez de everycomo mencionei no primeiro parágrafo. :) Obrigado pela captura!
ZER0
5

Você pode obter esse one-liner para fazer o que quiser usando as funções de seta Array.prototype.every , Object.is e ES6:

const all = arr => arr.every(x => Object.is(arr[0], x));
Noor
fonte
2
Por favor, descreva a solução que você está propondo.
il_raffa
3

Eu acho que a maneira mais simples de fazer isso é criar um loop para comparar cada valor ao próximo. Enquanto houver uma quebra na "cadeia", ela retornará falsa. Se o primeiro é igual ao segundo, o segundo é igual ao terceiro e assim por diante, podemos concluir que todos os elementos da matriz são iguais entre si.

dado um dado de matriz [], você pode 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
fonte
3
arr.length && arr.reduce(function(a, b){return (a === b)?a:false;}) === arr[0];
Martin
fonte
3

Atualizar nova solução: 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;

Atualizado com o ES6: o uso list.everyé a maneira mais rápida:

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

versão antiga:

      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
fonte
2

Você pode usar isto:

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

A função primeiro verifica se a matriz está vazia. Se for, seus valores são iguais. Caso contrário, ele filtra a matriz e pega todos os elementos diferentes do primeiro. Se não houver tais valores => a matriz contém apenas elementos iguais, caso contrário não.

Minko Gechev
fonte
1

A _.isEqual(object, other)função de sublinhado parece funcionar bem para matrizes. A ordem dos itens na matriz importa quando verifica a igualdade. Veja http://underscorejs.org/#isEqual .

Jon Onstott
fonte
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);
    }));
}
user4861889
fonte
Explique também o que você fez, em vez de apenas colar algum código.
Wouter J
1

É simples. Crie uma função e passe um parâmetro. Nessa função, copie o primeiro índice para uma nova variável. Em seguida, crie um loop for e faça um loop na matriz. Dentro de um loop, crie um loop while com uma condição que verifique se a nova variável criada é igual a todos os elementos no loop. se seu retorno igual true após o loop for concluído, retorne false dentro do loop 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
fonte
1

A resposta aceita funcionou muito bem, mas eu queria acrescentar um pouquinho. Não funcionou para mim usar ===porque estava comparando matrizes de matrizes de objetos; no entanto, em todo o meu aplicativo, usei o pacote de igualdade profunda rápida que recomendo vivamente. Com isso, meu código fica assim:

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

e meus dados ficam assim:

[  
  [
    {
      "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
fonte
1
  1. Crie uma sequência juntando-se à matriz.
  2. Crie string repetindo o primeiro caractere da matriz especificada
  3. combinar as duas cordas

	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']));

E você está FEITO!

Rahul Vala
fonte
1

Agora você pode usar conjuntos para fazer isso facilmente.

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
fonte
1

Você pode usar um loop 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
fonte
0

Bem, isso realmente não é muito complicado. Eu tenho uma forte suspeita de que você nem tentou. O que você faz é escolher o primeiro valor, salvá-lo na variável e, em um forloop, comparar todos os valores subsequentes com o primeiro.
Eu intencionalmente não compartilhei nenhum código. Descubra como foré usado e como as variáveis ​​são comparadas.

Tomáš Zato - Restabelecer Monica
fonte
8
Eu não gosto desta resposta. Ele não informaria se o segundo valor era o mesmo que o terceiro, etc. Obviamente, o loop aninhado faria isso, mas isso é conceitualmente diferente de um scripter iniciante.
Jromans
3
@jtromans: por causa da propriedade transitiva da igualdade, se A == B e A == C, então sabemos que B == C; você não precisa verificá-lo "manualmente" com um loop aninhado etc. A comparação repetida com um único valor (primeiro valor na matriz, não arbitrário :) é exatamente o que essa resposta sugere e a resposta aceita.
ov
@ov De fato, na minha pressa, eu interpretei mal a pergunta, que eu pensava que na época exigia mais do que apenas verificar se todos os valores são iguais (! duh).
Jromans
9
Não é complicado. E nem as outras respostas da página. Mas para mim, essa resposta é de longe a menos útil.
Charlie
1
Originalmente, ele pretendia enfatizar o OP, insistindo que ele tenta pensar antes de fazer perguntas.
Tomáš Zato - Restabelece Monica
0

Solução simples de uma linha, basta compará-la com uma matriz preenchida com a primeira entrada.

if(arr.join('') === Array(arr.length).fill(arr[0]).join(''))
pyviet
fonte
Isso não parece ser uma solução que pode ser usado em qualquer lugar
LU4
É bem perto de ok. Melhor seria algo como: function arrayOfSame (arr) {return (arr.join ('') == (new Array (arr.length + 1) .join (arr [0]))); }
Arkain 15/03
0

Outra maneira interessante quando você usa a sintaxe da função de seta 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

E quando você não deseja reutilizar a variável para o array (x):

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

O pôster anterior da OMI que usou array.every (...) tem a solução mais limpa.

Tomasz Szawara
fonte
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 o primeiro loop; sempre que detectar irregular, retorna "false"
  • O primeiro loop é executado e, se retornar falso, temos "false"
  • Quando não retorna false, significa que haverá true, então fazemos o segundo loop. E é claro que teremos "true" no segundo loop (porque o primeiro loop descobriu que NÃO é falso)
Jaden Tran
fonte
0

isso pode funcionar, você também pode usar o código de comentário que também funciona bem com o cenário fornecido.

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
fonte
0

Outra maneira com tamanho delimitado e lista organizada:

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

function isEqual(){

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

Você pode converter a matriz em um conjunto e verificar seu tamanho

No caso de entradas de matriz primitivo, isto é number, string:

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

No caso de matriz de objetos com algum campo a ser testado para equivalência, diga id:

const mapper = ({id}) => id
const isArrayWithEqualEntries = array => new Set(array.map(mapper)).size === 1
Simon
fonte
-4

No PHP, existe uma solução muito simples, com um método de linha:

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

Por exemplo :

$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

Isso é tudo.

Jerry
fonte