Перевірте, чи всі значення масиву рівні


190

Мені потрібно знайти масиви, де всі значення рівні. Який найшвидший спосіб це зробити? Чи повинен я переглядати його і просто порівнювати значення?

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

1
@TJCrowder Сподіваюся, ви вже думаєте про найкраще рішення;)
VisioN

2
@TJCrowder: Не кажучи вже про готовність запитуючих насправді приймати відповіді. Нещодавно користувачі, які мають 1 особу, часто запитують і запускають типи, які залишають, як тільки вони отримують відповідь, здатну скопіювати.
Cerbrus

1
Щось навколо цього підходу має спрацювати? a.join(',').split(a[0]).length === a.length + 1
Jashwant

1
@ TomášZato: "OP" означає "оригінальний плакат" (особа, яка задає питання).
TJ Crowder

Відповіді:


288
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()метод перевіряє, чи всі елементи в масиві проходять тест, реалізований наданою функцією.


10
Стислість - це душа дотепності
сварог

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
@Jan 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! наприклад, спробуйте [false, false, false] .reduce (функція (a, b) {return (a === b)? a: false;});
Джордж Флоренцос

3
@Martin: ["false", ""]повертається true: /
dalgard

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). Деякі старіші версії IE не підтримують розширення лише для прототипів елементів DOM.
TJ Crowder

4
Я не думаю, що це гарна ідея бути мавповими латками вбудованих прототипів. Якщо це зробити кілька бібліотек, це може призвести до несподіваної поведінки, яку дуже важко налагодити.
Марк Вільбур

1
@MarkWilbur +1, особливо якщо ти робиш цикл for..in на наступних масивах, ти потрапиш allValuesSameу цикл
Олів'є Понс

1
Я пішов вперед і модернізував це, не змінюючи наміру.
Пан Polywhirl

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

Блискуча. Тільки зауважте, що 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. Напр .: зменшити, відфільтрувати, кожен, якийсь
З. Хулла

де рідний для циклу, я думаю, що перевершує все це в 5
разів

9

Найкоротша відповідь за допомогою підкреслення / подачі

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

Або ви можете додати його до власних функцій масиву в 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;

Також працює.


Перший приклад у вас є назад. Повинно бути equals = !array.some( (v,i,a) => v!==a[0] ). Інакше ви просто перевіряєте, чи будь-яке значення дорівнює першому, що, звичайно, завжди буде правдою :)
Марк Кан

Не зовсім я використовував someзамість того, everyяк я згадував у першому пункті. :) Дякую за улов!
ZER0,


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

Оновити нове рішення: перевірити індекс

 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)Функція підкреслення, здається, добре працює для масивів. Порядок елементів у масиві має значення, коли він перевіряє рівність. Дивіться 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);
    }));
}

Будь ласка, поясніть, що ви робили, а не просто вставляли якийсь код.
Wouter J

1

Це просто. Створіть функцію та передайте параметр. У цій функції скопіюйте перший індекс у нову змінну. Потім створіть цикл і цикл через масив. Всередині циклу створіть цикл while з умовою, що перевіряє, чи нова створена змінна рівна всім елементам циклу. якщо його рівне повернення вірно після циклу for, завершує інше повернення 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;
}

1

Прийняв відповідь працював великий , але я хотів би додати трохи - трохи. Мені це не вдалося використовувати, ===оскільки я порівнював масиви масивів об’єктів, однак у всьому моєму додатку я використовував швидкий-глибокий рівний пакет, який дуже рекомендую. З цим мій код виглядає приблизно так:

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

Ви можете використовувати цикл:

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 Дійсно, я поспішаю перечитати запитання, яке, на мою думку, вимагало більше, ніж просто перевірка рівності всіх значень (! duh).
jtromans

9
Це не складно. І інших відповідей на сторінці немає. Але мені ця відповідь, безумовно, найменш корисна.
Чарлі

1
Спочатку мала на меті зробити сильну точку до ОП, наполягаючи, що він намагається подумати, перш ніж задавати питання.
Томаш Зато - Відновіть Моніку

0

Просте рішення з одного рядка, просто порівняйте його з масивом, заповненим першим записом.

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

Це не схоже на рішення, яке можна використовувати де завгодно
1616

Це досить близько до ок. Краще було б щось на зразок: функція arrayOfSame (arr) {return (arr.join ('') == (новий масив (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

Попередній плакат IMO, який використовував 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, це означає, що це буде правда, тому ми робимо другу петлю. І звичайно, у нас буде "true" з другого циклу (тому що перший цикл виявив, що НЕ помилково)

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

Це все.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.