Controlla se tutti i valori dell'array sono uguali


190

Devo trovare array in cui tutti i valori siano uguali. Qual è il modo più veloce per farlo? Dovrei scorrere attraverso di esso e solo confrontare i valori?

['a', 'a', 'a', 'a'] // true
['a', 'a', 'b', 'a'] // false

1
@TJCrowder Scommetto che stai già pensando alla soluzione migliore;)
VisioN

2
@TJCrowder: per non parlare della volontà dei richiedenti di accettare effettivamente le risposte. Gli utenti con 1 rappresentante spesso sembrano chiedere ed eseguire tipi che escono non appena hanno una risposta in grado di copiare e incollare, ultimamente.
Cerbrus,

1
Qualcosa attorno a questo approccio dovrebbe funzionare? a.join(',').split(a[0]).length === a.length + 1
Jashwant,

1
@ TomášZato: "OP" significa "poster originale" (la persona che pone la domanda).
TJ Crowder,

Risposte:


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

O one-liner:

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

Array.prototype.every (da MDN): il every()metodo verifica se tutti gli elementi dell'array superano il test implementato dalla funzione fornita.


11
La brevità è l'anima dell'ingegno
svarog,

1
Ho creato un caso jsperf . Questo metodo supera la maggior parte dei candidati.
Junliang Huang,

1
const everythings_equal = array => array.every(thing => thing === array[0]);
Константин Ван

8
Utilizzare someinvece di every: arr.some( v => v !== arr[0] ). Questo tornerà presto sul primo elemento trovato ineguale arr[0].
Jan

2
@Jan everyfa anche ritorno presto.
Golopot,

111

Modifica: Be a ninja rosso:

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

risultati:

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" 

Avvertimento:

var array = [] => result: TypeError thrown

Questo perché non passiamo un valore iniziale . Quindi, potresti voler controllare array.lengthprima.


5
potrebbe essere un po 'tardi alla festa ... penso che questo non funzioni se il tuo array è fatto di falses! ad esempio provare [false, false, false] .reduce (funzione (a, b) {return (a === b)? a: false;});
George Flourentzos,

3
@Martin: ["false", ""]ritorna true: /
dalgard

6
Questo può essere raggiunto di un livello utilizzando NaN. Poiché entrambi NaN === NaNe NaN !== NaNsono falsi, garantisce che, una volta previmpostato su NaN, nessun valore può eliminarlo. Anche l'aggiunta di una doppia negazione converte i risultati in truee false, poiché NaNè falsa. Forma finale:!!array.reduce(function(a, b){ return (a === b) ? a : NaN; });
Filipe Silva,

3
DOWNVOTATO . E se gli elementi fossero uguali ma falsi ?
Константин Ван

3
Ho effettuato il downgrade perché non funziona con valori booleani.
Tyguy7,

62

Questo funziona Si crea un metodo sull'array utilizzando il 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;
  }
}

Chiamalo in questo modo:

let a = ['a', 'a', 'a'];
let b = a.allValuesSame(); // true
a = ['a', 'b', 'a'];
b = a.allValuesSame();     // false

5
molto bello, ma attenzione: IE non supporta questo modo di assegnare prototipi. Lo uso comunque.
Tomáš Zato - Ripristina Monica il

5
@ TomášZato: IE supporta l'aumento del Array.prototypegiusto (anche IE6). Sono solo i prototipi di elementi DOM che alcune versioni precedenti di IE non supportano il potenziamento.
TJ Crowder,

4
Non credo sia una buona idea essere prototipi integrati per l'applicazione di patch scimmia. Se lo fanno più librerie, può portare a comportamenti imprevisti che è molto difficile eseguire il debug.
Mark Wilbur,

1
@MarkWilbur +1 specialmente se esegui un ciclo for..in successivi array, entrerai allValuesSamenel loop
Olivier Pons

1
Sono andato avanti e ho modernizzato questo, senza alterare l'intento.
Mr. Polywhirl

30

In JavaScript 1.6, puoi utilizzare Array.every:

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

Probabilmente avrai bisogno di alcuni controlli di integrità, ad esempio quando l'array non ha elementi. (Inoltre, questo non funzionerà quando tutti gli elementi sono NaNfiniti NaN !== NaN, ma questo non dovrebbe essere un problema ... giusto?)


30

È possibile trasformare l'array in un set. Se la dimensione del set è uguale a 1, tutti gli elementi dell'array sono uguali.

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

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

Brillante. Basta notare che allEqual([NaN, NaN])truein questo caso.
Константин Ван

12

E per il confronto delle prestazioni ho anche fatto un benchmark:

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

risultati:

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)

Quindi apparentemente l'utilizzo di array.some () è il metodo più veloce di quelli campionati.


3
Buona idea per verificare cosa c'è di più performante qui. Il motivo per cui Array#somea volte sovraperformerà è che una volta che la funzione di callback ritorna vera, smette di iterare. Quindi, se tutti gli elementi sono effettivamente uguali, le prestazioni dovrebbero essere identiche Array#every. E le prestazioni relative quando tutti gli elementi non sono uguali varieranno in base all'indice del primo elemento non corrispondente.
danmactough,

3
Ben fatto. Avresti potuto nominare ciascuno con la funzione usata lol. Ad esempio: ridurre, filtrare, ogni, alcuni
Z. Khullah

dov'è il ciclo nativo, scommetto che supera di tutti questi un fattore 5
PirateApp,

9

Risposta più breve usando underscore / lodash

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

spec:

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

modificare:

O ancora più breve, ispirato alla risposta di Tom:

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

spec:

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

6

Se stai già utilizzando underscore.js , ecco un'altra opzione che utilizza _.uniq:

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

_.uniqrestituisce una versione dell'array senza duplicati. Se tutti i valori sono uguali, la lunghezza sarà 1.

Come menzionato nei commenti, dato che potresti aspettarti un array vuoto da restituire true, allora dovresti anche verificare quel caso:

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

Ma se l'array è vuoto, la risposta verrà restituita false. Mentre penso che dovrebbe essere true. Passaggio a .length <= 1deve essere abbastanza però.
media Joe

@Kasztan è un punto giusto. Ho aggiornato la mia risposta per coprire quel caso.
Tom Fenech,

6

Sì, puoi controllarlo anche usando il filtro come di seguito, molto semplice, controllando che tutti i valori siano gli stessi del primo:

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

inoltre può essere eseguito usando tutti i metodi dell'array:

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

e puoi controllare le tue matrici come di seguito:

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

Oppure puoi aggiungerlo alle funzionalità dell'array nativo in JavaScript se lo riutilizzi molto:

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

e puoi controllare le tue matrici come di seguito:

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

5

Puoi usare Array.everyse supportato:

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

L'approccio alternativo di un ciclo potrebbe essere qualcosa di simile sort

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

Oppure, se gli articoli sono come la domanda, qualcosa di sporco come:

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

Funziona anche.


Hai il primo esempio al contrario. Dovrebbe essere equals = !array.some( (v,i,a) => v!==a[0] ). Altrimenti stai solo verificando che qualsiasi valore sia uguale al primo che, ovviamente, sarà sempre vero :)
Mark Kahn

Non esattamente, ho usato someinvece di everycome ho menzionato nel primo paragrafo. :) Grazie per la cattura!
ZER0

5

È possibile ottenere questo one-liner per fare ciò che si desidera utilizzando le funzioni freccia Array.prototype.every , Object.is ed ES6:

const all = arr => arr.every(x => Object.is(arr[0], x));

2
Per favore, descrivi la soluzione che stai proponendo.
il_raffa,

3

Penso che il modo più semplice per farlo sia quello di creare un ciclo per confrontare ciascun valore con il successivo. Finché si verifica un'interruzione nella "catena", restituisce false. Se il primo è uguale al secondo, il secondo è uguale al terzo e così via, allora possiamo concludere che tutti gli elementi dell'array sono uguali tra loro.

dati un array di dati [], quindi è possibile utilizzare:

for(x=0;x<data.length - 1;x++){
    if (data[x] != data[x+1]){
        isEqual = false;            
    }
}
alert("All elements are equal is " + isEqual);

3
arr.length && arr.reduce(function(a, b){return (a === b)?a:false;}) === arr[0];

3

Aggiorna nuova soluzione: controlla indice

 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;

Aggiornato con ES6: l'uso list.everyè il modo più veloce:

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

vecchia versione:

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

2

Puoi usare questo:

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

La funzione controlla innanzitutto se l'array è vuoto. Se è i suoi valori sono uguali .. Altrimenti filtra l'array e accetta tutti gli elementi che sono diversi dal primo. Se non ci sono tali valori => l'array contiene solo elementi uguali, altrimenti non lo è.



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

Spiega anche cosa hai fatto invece di incollare un po 'di codice.
Wouter J,

1

È semplice. Crea una funzione e passa un parametro. In quella funzione copia il primo indice in una nuova variabile. Quindi creare un ciclo for e passare in rassegna l'array. All'interno di un ciclo crea un ciclo while con una condizione che controlla se la nuova variabile creata è uguale a tutti gli elementi nel ciclo. se il suo uguale ritorno è vero dopo che il ciclo for è completo, altrimenti restituisce false nel 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;
}

1

La risposta accettata ha funzionato alla grande ma volevo aggiungere un pochino. Non ha funzionato per me ===perché stavo confrontando le matrici di matrici di oggetti, tuttavia in tutta la mia app ho usato il pacchetto fast-deep-equal che consiglio vivamente. Detto questo, il mio codice è simile al seguente:

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

e i miei dati si presentano così:

[  
  [
    {
      "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
    }
  ]
]

1
  1. Crea una stringa unendo l'array.
  2. Crea una stringa ripetendo il primo carattere dell'array specificato
  3. abbina entrambe le stringhe

	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 sei fatto!


1

Ora puoi usare i set per farlo 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);


1

È possibile utilizzare un ciclo for:

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

0

Bene, questo non è davvero molto complicato. Ho un forte sospetto che tu non abbia nemmeno provato. Quello che fai è scegliere il primo valore, salvarlo nella variabile e quindi, all'interno di un forciclo, confrontare tutti i valori successivi con il primo.
Non ho intenzionalmente condiviso alcun codice. Scopri come forviene utilizzato e come vengono confrontate le variabili.


8
Non mi piace questa risposta. Non ti farebbe sapere se il secondo valore era lo stesso del terzo, ecc. Ovviamente il ciclo nidificato lo farebbe, ma è concettualmente diverso da uno scripter principiante.
jtromans,

3
@jtromans: a causa della proprietà transitiva dell'uguaglianza, se A == B e A == C allora conosciamo B == C; non è necessario verificarlo "manualmente" con un ciclo nidificato, ecc. Ripetere il confronto con un singolo valore (primo valore nell'array, non arbitrario :) è esattamente ciò che suggerisce questa risposta, così come la risposta accettata.
Ov

@ov In effetti, nella mia fretta ho letto male la domanda, che pensavo in quel momento richiedesse qualcosa di più del semplice controllo che tutti i valori fossero uguali (! duh).
jtromans,

9
Non è complicato E nemmeno le altre risposte sulla pagina. Ma per me questa risposta è di gran lunga la meno utile.
Charlie,

1
Inizialmente aveva lo scopo di dare un punto di forza all'OP insistendo sul fatto che lui cercasse di pensare prima di porre domande.
Tomáš Zato - Ripristina Monica

0

Semplice soluzione a una riga, basta confrontarla con un array riempito con la prima voce.

if(arr.join('') === Array(arr.length).fill(arr[0]).join(''))

Non sembra una soluzione che può essere utilizzata ovunque
Lu4,

È abbastanza vicino all'ok. Meglio sarebbe qualcosa del tipo: function arrayOfSame (arr) {return (arr.join ('') == (new Array (arr.length + 1) .join (arr [0]))); }
Arkain,

0

Un altro modo interessante quando si utilizza la sintassi della funzione freccia 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 non vuoi riutilizzare la variabile per array (x):

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

Poster precedente dell'IMO che utilizzava array.every (...) ha la soluzione più pulita.


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; }
  }
}
  • Per il primo ciclo; ogni volta che rileva irregolarità, restituisce "false"
  • Il primo ciclo viene eseguito e se restituisce false, abbiamo "false"
  • Quando non restituisce false, significa che ci sarà true, quindi facciamo il secondo loop. E ovviamente avremo "true" dal secondo loop (perché il primo loop ha riscontrato che NON è falso)

0

questo potrebbe funzionare, puoi usare anche il codice di commento che si sveglia bene anche con lo scenario dato.

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();


0

Un altro modo con dimensioni delimitate ed elenco organizzato:

array1 = [1,2,3]; array2 = [1,2,3];

function isEqual(){

    return array1.toString()==array2.toString();
}

0

È possibile convertire l'array in un set e verificarne le dimensioni

Nel caso di elementi dell'array primitivi, cioè number, string:

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

In caso di array di oggetti con qualche campo da verificare per l'equivalenza, dire id:

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

-4

In PHP esiste una soluzione molto semplice, un metodo a una riga:

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

Per esempio :

$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

È tutto.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.