2013-02-12 2 views
64

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

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

@ T.J.Crowder я уверен, вы уже думать о лучшем решении;) – VisioN

+1

@ T.J.Crowder: Не говоря уже о готовности аскеров на самом деле принимать ответы. Пользователям с 1 реком часто кажется, что задают и запускают типы, которые уходят, как только у них есть ответ на вставку-вставку, в последнее время. – Cerbrus

+0

Очень правильные вещи, которые вы здесь говорите. Но stackoverflow очень уязвим для простых вопросов. Просто проверьте верхнюю страницу голосов. –

ответ

89

Edit: Быть Красный Ниндзя:

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

Это происходит потому, что мы не сдали InitialValue , Таким образом, вы можете сначала проверить array.length.

+1

+1 Я попытался придумать «уменьшить» версию этого сам, но не смог. Это довольно круто. –

+3

может немного опоздать на вечеринку ... Я думаю, что это не сработает, если ваш массив сделан из 'false's! , например try [false, false, false] .reduce (function (a, b) {return (a === b)? A: false;}); –

+0

Малое изменение: arr.reduce (function (a, b) {return (a === b)? A: false;}) === arr [0]; – Martin

3

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

+1

это должно быть принято. – alix

+5

Мне не нравится этот ответ. Это не даст вам знать, было ли второе значение таким же, как третье, и т. Д. Очевидно, что вложенный цикл будет делать это, но это принципиально отличается от начинающего скриптера. – jtromans

+3

@jtromans: из-за транзитивного свойства равенства, если A == B и A == C, тогда мы знаем B == C; вам не нужно проверять его «вручную» с вложенным циклом и т. д. Повторение сравнения с одним значением (первое значение в массиве, а не произвольное) - именно то, что предлагает этот ответ, а также принятый ответ. –

61

Это работает. Вы создаете метод в массиве с использованием прототипа.

Array.prototype.allValuesSame = function() { 

    for(var i = 1; i < this.length; i++) 
    { 
     if(this[i] !== this[0]) 
      return false; 
    } 

    return true; 
} 

Вызов это таким образом:

var a = ['a', 'a', 'a']; 
var b = a.allValuesSame(); //true 
a = ['a', 'b', 'a']; 
b = a.allValuesSame(); //false 
+4

очень приятно, но будьте осторожны: IE не поддерживает этот способ назначения прототипов. Я использую его в любом случае. –

+0

Вам не нужен блок 'else', потому что' if' вернет значение из функции, прежде чем код ниже будет иметь возможность быть выполненным, если условие в 'if' равно' true '. Если это 'false',' else' должен быть выполнен любым способом, не нужно обертывать его в дополнительный '{}' 's – Cerbrus

+5

@ TomášZato: IE поддерживает расширение «Array.prototype» просто отлично (даже IE6). Это только прототипы элементов DOM, которые некоторые более старые версии IE не поддерживают увеличение. –

2

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

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

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

27

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

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

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

+1

Dat уродливая копия/paste из всех/любых функций Python ... –

2

Что-то вокруг этого подхода должно работать.

a.join(',').split(a[0]).length === a.length + 1 
+1

Я уже некоторое время поддерживал, а затем понял, что это будет сообщать следующее: все равно: ["a", "b", "aa"]. Вот досада! –

+0

Да, конечно. Облом. –

+0

@ScottSauyet Хороший улов, я об этом не думал и, таким образом, сказал, что-то вокруг этого подхода. Btw, это соответствует потребностям OP, поскольку мне кажется, что все элементы массива являются символами. – Jashwant

4

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

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

+1

Благодарим вас за то, что вы оставили ответы на все вопросы в одном ... –

+0

У вас есть первый пример назад. Должно быть 'equals =! Array.some ((v, i, a) => v! == a [0])'. В противном случае вы просто проверяете, что любое значение равно первому, которое, конечно, всегда будет истинным :) –

+0

Не совсем, я использовал 'some' вместо' every', как я упоминал в первом абзаце. :) Спасибо за улов! – ZER0

1

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

9

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

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() является самым быстрым способом из тех выборок.

+2

Хорошая идея, чтобы проверить, что более показательно здесь. Причина, по которой 'Array # some' будет иногда превосходить, заключается в том, что после того, как функция обратного вызова вернёт true, она прекращает итерацию. Итак, если все элементы на самом деле равны, производительность должна быть идентичной «Array # every». И относительная производительность, когда все элементы не равны, будет зависеть от индекса первого несогласованного элемента. – danmactough

+0

Ницца. Вы могли бы назвать их с помощью функции lol. Например: уменьшить, фильтровать, каждый, –

3

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

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

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

Это может быть самое быстрое решение: http://jsperf.com/array-equal-values ​​ – Tieme

2

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

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)); 
     } 
3
arr.length && arr.reduce(function(a, b){return (a === b)?a:false;}) === arr[0]; 
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); 
    })); 
} 
+0

Пожалуйста, также объясните, что вы сделали, а не просто вставляете какой-либо код. –

8

Кратчайший ответ, используя подчеркивание/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; 
} 
+0

Но если массив пуст, ваш ответ вернет 'false'. Хотя я думаю, что это должно быть «правда». Однако достаточно переходить на '.length <= 1'. – Kasztan

+0

@ Kasztan, это справедливая точка. Я обновил свой ответ, чтобы рассмотреть этот случай. –

4

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

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

Пожалуйста, опишите решение, которое вы предлагаете. –

53
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): Метод каждый() проверяет, все ли элементы в массиве проходят испытание, реализованный предоставленной функцией.

+1

Brevity - это душа остроумия – svarog

+0

Лучшее использование языка. – SoEzPz

+1

Я создал [случай jsperf] (https://jsperf.com/all-array-elements-equals). Этот метод превосходит большинство кандидатов. –

-2

В PHP есть решение очень простое, одна линия метод:

(COUNT (array_count_values ​​($ массив)) == 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 

Вот все.

0

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

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

Это не похоже на решение, которое можно использовать где угодно – Lu4

+0

Это довольно близко к окну. Лучше было бы что-то вроде: function arrayOfSame (arr) { return (arr.join ('') == (новый массив (arr.length + 1) .join (arr [0]))); } – Arkain

5

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

//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 

Или вы можете добавить его в нативный массиве функциональных возможностей в 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 
6

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

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

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

** Блестящий. ** Просто обратите внимание, что 'allEqual ([NaN, NaN])' дает 'true' в этом случае. –

1

Его Простой. Создайте функцию и передайте параметр. В этой функции скопируйте первый индекс в новую переменную. Затем создайте цикл for и цикл через массив. Внутри цикла создайте цикл while с условием, проверяющим, равна ли новая созданная переменная всем элементам цикла. , если его равное значение true после того, как цикл for завершает else, возвращает false внутри цикла while.

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