Проверьте, все ли значения массива равны

190

Мне нужно найти массивы, где все значения равны. Какой самый быстрый способ сделать это? Должен ли я пройти через это и просто сравнить значения?

['a', 'a', 'a', 'a'] // true
['a', 'a', 'b', 'a'] // false
Marvin3
источник
1
@TJCrowder Бьюсь об заклад, вы уже думаете о лучшем решении;)
VisioN
2
@TJCrowder: Не говоря уже о готовности спрашивающих принимать ответы. Пользователи с 1 повторением часто, кажется, спрашивают и запускают типы, которые выходят, как только у них появляется ответ с возможностью копирования и вставки, в последнее время.
Цербр
1
Что-то вокруг этого подхода должно работать? a.join(',').split(a[0]).length === a.length + 1
Jashwant
1
@ TomášZato: «OP» означает «оригинальный постер» (человек, задающий вопрос).
TJ Crowder

Ответы:

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

Или однострочник:

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

Array.prototype.every (из MDN): every()метод проверяет, все ли элементы массива проходят тест, реализованный предоставленной функцией.

golopot
источник
12
Краткость - душа ума
Сварог
1
Я создал случай jsperf . Этот метод превосходит большинство кандидатов.
Юнлян Хуан
1
const everythings_equal = array => array.every(thing => thing === array[0]);
Константин Ван
8
Используйте someвместо every: arr.some( v => v !== arr[0] ). Это вернется рано после того, как первый элемент окажется неравным arr[0].
Jan
2
@ Ян everyтоже рано возвращается.
Голопот
111

Редактировать: Быть красным ниндзя:

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

Полученные результаты:

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" 

Предупреждение:

var array = [] => result: TypeError thrown

Это потому, что мы не передаем начальное значение . Итак, вы можете проверить в array.lengthпервую очередь.

Мартин
источник
5
может быть немного поздно для вечеринки ... я думаю, что это не сработает, если ваш массив состоит из falses! например try [false, false, false] .reduce (function (a, b) {return (a === b)? a: false;});
Джордж Флоурентзос
3
@Martin: ["false", ""]возвращается true: /
Далгард
6
Это может быть принято на ступеньку выше с помощью NaN. Поскольку оба NaN === NaNи NaN !== NaNявляются ложными, это гарантирует, что, если для параметра prevустановлено значение NaN, никакое значение не может его убрать. Кроме того, добавление в двойное отрицание преобразует результаты в trueи false, поскольку NaNэто ложно. Окончательная форма:!!array.reduce(function(a, b){ return (a === b) ? a : NaN; });
Филипе Сильва
3
СКАЧАТЬ . Что если элементы равны, но ложны ?
Константин Ван
3
Я понижен, потому что это не работает с логическими значениями.
Tyguy7
62

Это работает. Вы создаете метод в Array, используя прототип.

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

Назовите это так:

let a = ['a', 'a', 'a'];
let b = a.allValuesSame(); // true
a = ['a', 'b', 'a'];
b = a.allValuesSame();     // false
Роберт Фрике
источник
5
очень хорошо, но будьте осторожны: IE не поддерживает этот способ назначения прототипов. Я использую это так или иначе.
Томаш Зато - Восстановить Монику
5
@ TomášZato: IE поддерживает увеличение Array.prototypeпросто отлично (даже IE6). Это только прототипы элементов DOM, которые некоторые старые версии IE не поддерживают расширение.
TJ Crowder
4
Я не думаю, что это хорошая идея, чтобы обезьяна исправляла встроенные прототипы. Если это делают несколько библиотек, это может привести к неожиданному поведению, которое очень сложно отладить.
Марк Уилбур
1
@MarkWilbur +1, особенно если вы выполните цикл for..in для следующих массивов, вы попадете allValuesSameв цикл
Olivier Pons
1
Я пошел дальше и модернизировал это, не изменяя намерения.
г-н Поливирл
30

В JavaScript 1.6 вы можете использовать Array.every:

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

Возможно, вам понадобятся некоторые проверки работоспособности, например, когда массив не имеет элементов. (Кроме того, это не будет работать, когда все элементы NaNс тех пор NaN !== NaN, но это не должно быть проблемой ... верно?)

Маттиас Буэленс
источник
30

Вы можете превратить массив в набор. Если размер набора равен 1, то все элементы массива равны.

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

allEqual(['a', 'a', 'a', 'a']); // true
allEqual(['a', 'a', 'b', 'a']); // false
Хай Тран
источник
Brilliant. Просто обратите внимание, что allEqual([NaN, NaN])дает trueв этом случае.
Константин Ван
12

И для сравнения производительности я также сделал тест:

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

Полученные результаты:

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)

Таким образом, очевидно, что использование встроенного array.some () является самым быстрым методом из опрошенных.

Мартин
источник
3
Хорошая идея, чтобы проверить, что является более производительным здесь. Причина, по которой Array#someиногда приходится опережать, состоит в том, что как только функция обратного вызова возвращает true, она прекращает итерацию. Таким образом, если все элементы на самом деле равны, производительность должна быть идентичной Array#every. И относительная производительность, когда все элементы не равны, будет варьироваться в зависимости от индекса первого несоответствующего элемента.
danmactough
3
Хороший. Вы могли бы назвать каждого с помощью функции lol. Например: уменьшить, фильтровать, каждый, некоторые
Z. Khullah
где родной для цикла, держу пари, что превосходит все это в 5 раз
PirateApp
9

Кратчайший ответ с использованием подчеркивания / lodash

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

спецификация:

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

редактировать:

Или даже короче, вдохновленный ответом Тома:

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

спецификация:

elementsEqual2(null) // true (beware, it's different than above)
elementsEqual2([]) // true
elementsEqual2({}) // true
elementsEqual2([1]) // true
elementsEqual2([1,2]) // false
elementsEqual2(NaN) // true
средний Джо
источник
6

Если вы уже используете underscore.js , то вот еще один вариант использования _.uniq:

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

_.uniqвозвращает версию массива без дубликатов. Если все значения одинаковы, то длина будет 1.

Как упоминалось в комментариях, учитывая, что вы можете ожидать возврата пустого массива true, вам также следует проверить этот случай:

function allEqual(arr) {
    return arr.length === 0 || _.uniq(arr).length === 1;
}
Том Фенек
источник
Но если массив пуст, ваш ответ вернется false. Пока думаю так и должно быть true. Переход на .length <= 1должно быть достаточно, хотя.
среднем Джо
@Kasztan это справедливо. Я обновил свой ответ, чтобы покрыть этот случай.
Том Фенек,
6

Да, вы можете проверить это также с помощью фильтра, как показано ниже, очень просто, проверяя, что все значения совпадают с первым:

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

также может быть сделано с использованием каждого метода в массиве:

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

и вы можете проверить свои массивы, как показано ниже:

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

Или вы можете добавить его к собственным функциям Array в JavaScript, если вы многократно его используете:

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

и вы можете проверить свои массивы, как показано ниже:

['a', 'a', 'a', 'a'].sameValues(); // true
['a', 'a', 'b', 'a'].sameValues(); // false
Алиреза
источник
5

Вы можете использовать, Array.everyесли поддерживается:

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

Альтернативный подход цикла может быть что-то вроде sort

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

Или, если элементы похожи на вопрос, что-то грязное, как:

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

Также работает.

ZER0
источник
У вас есть первый пример в обратном направлении. Должно быть equals = !array.some( (v,i,a) => v!==a[0] ). В противном случае вы просто проверяете, что любое значение равно первому, что, конечно, всегда будет верным :)
Марк Кан,
Не совсем, я использовал someвместо того, everyчто я упоминал в первом абзаце. :) Спасибо за улов!
ZER0
5

Вы можете заставить этот однострочник делать то, что вы хотите, используя функции стрелок Array.prototype.every , Object.is и ES6:

const all = arr => arr.every(x => Object.is(arr[0], x));
Noor
источник
2
Пожалуйста, опишите решение, которое вы предлагаете.
il_raffa
3

Я думаю, что самый простой способ сделать это - создать цикл для сравнения каждого значения с другим. Пока есть разрыв в «цепочке», он будет возвращать ложь. Если первый равен второму, второй равен третьему и т. Д., То можно сделать вывод, что все элементы массива равны друг другу.

учитывая массив данных [], то вы можете использовать:

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

Обновите новое решение: проверьте индекс

 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;

Обновлено с ES6: использование list.every это самый быстрый способ:

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

старая версия:

      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

Вы можете использовать это:

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

Функция сначала проверяет, является ли массив пустым. Если это так, его значения равны. В противном случае он фильтрует массив и принимает все элементы, отличные от первого. Если таких значений нет => массив содержит только равные элементы, иначе это не так.

Минько Гечев
источник
1

_.isEqual(object, other)Функция Underscore, кажется, хорошо работает для массивов. Порядок элементов в массиве имеет значение, когда он проверяет равенство. Смотрите http://underscorejs.org/#isEqual .

Джон Онстотт
источник
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
источник
Пожалуйста, объясните, что вы сделали, вместо того, чтобы просто вставить код.
Wouter J
1

Это просто. Создайте функцию и передайте параметр. В этой функции скопируйте первый индекс в новую переменную. Затем создайте цикл for и переберите массив. Внутри цикла создайте цикл while с условием проверки, равна ли вновь созданная переменная всем элементам цикла. если его равное возвращаемое значение true после завершения цикла for, иначе возвращает ложное значение внутри цикла 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

Принял ответ работал большой , но я хотел бы добавить чуть - чуть. Мне это не помогло, ===потому что я сравнивал массивы массивов объектов, однако в своем приложении я использовал пакет fast-deep-equal , который я очень рекомендую. С этим мой код выглядит так:

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

и мои данные выглядят так:

[  
  [
    {
      "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. Создайте строку, присоединившись к массиву.
  2. Создать строку путем повторения первого символа данного массива
  3. сопоставить обе строки

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

И ты СДЕЛАН!

Рахул Вала
источник
1

Теперь вы можете использовать наборы, чтобы сделать это легко.

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

Вы можете использовать цикл 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

Ну, это действительно не очень сложно. У меня есть сильное подозрение, что ты даже не попробовал. Вы выбираете первое значение, сохраняете его в переменной, а затем в forцикле сравниваете все последующие значения с первым.
Я намеренно не поделился кодом. Найдите, как forиспользуется и как сравниваются переменные.

Томаш Зато - Восстановить Монику
источник
8
Мне не нравится этот ответ. Он не даст вам знать, если второе значение будет таким же, как третье, и т. Д. Очевидно, что вложенный цикл сделает это, но концептуально отличается от начинающего сценариста.
jtromans
3
@jtromans: из-за переходного свойства равенства, если A == B и A == C, то мы знаем B == C; вам не нужно проверять это «вручную» с помощью вложенного цикла и т. д. Повторение сравнения с одним значением (первое значение в массиве, а не произвольное значение :) - это именно то, что предлагает этот ответ, а также принятый ответ.
OV
@ov Действительно, в спешке я неправильно понял вопрос, который, как мне показалось, требовал в то время большего, чем просто проверка того, что все значения равны (! duh).
jtromans
9
Это не сложно. И нет других ответов на странице. Но для меня этот ответ является наименее полезным.
Чарли
1
Первоначально он был призван подчеркнуть, что он пытается подумать, прежде чем задавать вопросы.
Томаш Зато - Восстановить Монику
0

Простое однострочное решение, просто сравните его с массивом, заполненным первой записью.

if(arr.join('') === Array(arr.length).fill(arr[0]).join(''))
pyviet
источник
Это не похоже на решение, которое можно использовать где угодно
Lu4
Это довольно близко к ок. Лучше было бы что-то вроде: function arrayOfSame (arr) {return (arr.join ('') == (new Array (arr.length + 1) .join (arr [0]))); }
Аркаин
0

Еще один интересный способ использования синтаксиса функции стрелки 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

И когда вы не хотите повторно использовать переменную для массива (x):

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

Предыдущий постер ИМО, который использовал array.every (...), имеет самое чистое решение.

Томаш Шавара
источник
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; }
  }
}
  • Для первого цикла; всякий раз, когда он обнаруживает неравномерность, возвращает «ложь»
  • Первый цикл выполняется, и если он возвращает false, у нас есть «false»
  • Когда он не возвращает false, это означает, что будет true, поэтому мы делаем второй цикл. И, конечно, у нас будет «true» из второго цикла (потому что первый цикл обнаружил, что это НЕ false)
Джейден Тран
источник
0

это может сработать, вы также можете использовать код комментария, который также хорошо работает с заданным сценарием.

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

Другой способ с ограниченным размером и упорядоченным списком:

массив1 = [1,2,3]; массив2 = [1,2,3];

function isEqual(){

    return array1.toString()==array2.toString();
}
Фабио Бальбино
источник
0

Вы можете конвертировать массив в набор и проверить его размер

В случае примитивных элементов массива, то есть number, string:

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

В случае массива объектов с некоторым полем, которое нужно проверить на эквивалентность, скажите id:

const mapper = ({id}) => id
const isArrayWithEqualEntries = array => new Set(array.map(mapper)).size === 1
Саймон
источник
-4

В PHP есть решение очень простой, однострочный метод:

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

Например :

$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

Вот и все.

Джерри
источник