I need to find arrays where all values are equal. What's the fastest way to do this? Should I loop through it and just compare values?
['a', 'a', 'a', 'a'] // true
['a', 'a', 'b', 'a'] // false
const allEqual = arr => arr.every( v => v === arr[0] )
allEqual( [1,1,1,1] ) // true
Or one-liner:
[1,1,1,1].every( (val, i, arr) => val === arr[0] ) // true
Array.prototype.every (from MDN) :
The every()
method tests whether all elements in the array pass the test implemented by the provided function.
This works. You create a method on Array by using prototype.
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;
}
}
Call this in this way:
let a = ['a', 'a', 'a'];
let b = a.allValuesSame(); // true
a = ['a', 'b', 'a'];
b = a.allValuesSame(); // false
In JavaScript 1.6, you can use Array.every
:
function AllTheSame(array) {
var first = array[0];
return array.every(function(element) {
return element === first;
});
}
You probably need some sanity checks, e.g. when the array has no elements. (Also, this won't work when all elements are NaN
since NaN !== NaN
, but that shouldn't be an issue... right?)
You can turn the Array into a Set. If the size of the Set is equal to 1, then all elements of the Array are equal.
function allEqual(arr) {
return new Set(arr).size == 1;
}
allEqual(['a', 'a', 'a', 'a']); // true
allEqual(['a', 'a', 'b', 'a']); // false
And for performance comparison I also did a 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];
});
}
Results:
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)
So apparently using builtin array.some() is the fastest method of the ones sampled.
Shortest answer using 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
edit:
Or even shorter, inspired by Tom's answer:
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
Yes, you can check it also using filter as below, very simple, checking every values are the same as the first one:
//ES6
function sameValues(arr) {
return arr.filter((v,i,a)=>v===a[0]).length === arr.length;
}
also can be done using every method on the array:
//ES6
function sameValues(arr) {
return arr.every((v,i,a)=>v===a[0]);
}
and you can check your arrays like below:
sameValues(['a', 'a', 'a', 'a']); // true
sameValues(['a', 'a', 'b', 'a']); // false
Or you can add it to native Array functionalities in JavaScript if you reuse it a lot:
//ES6
Array.prototype.sameValues = Array.prototype.sameValues || function(){
this.every((v,i,a)=>v===a[0]);
}
and you can check your arrays like below:
['a', 'a', 'a', 'a'].sameValues(); // true
['a', 'a', 'b', 'a'].sameValues(); // false
You can get this one-liner to do what you want using Array.prototype.every, Object.is, and ES6 arrow functions:
const all = arr => arr.every(x => Object.is(arr[0], x));
arr.length && arr.reduce(function(a, b){return (a === b)?a:false;}) === arr[0];
Update new solution: check index
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;
Updated with ES6:
Use list.every
is the fastest way:
let a = ['a', 'a', 'b', 'a'];
let check = (list) => list.every(item => item === list[0]);
old version:
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));
}
Underscore's _.isEqual(object, other)
function seems to work well for arrays. The order of items in the array matter when it checks for equality. See http://underscorejs.org/#isEqual.
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);
}));
}
Its Simple. Create a function and pass a parameter. In that function copy the first index into a new variable. Then Create a for loop and loop through the array. Inside a loop create an while loop with a condition checking whether the new created variable is equal to all the elements in the loop. if its equal return true after the for loop completes else return false inside the while loop.
function isUniform(arra){
var k=arra[0];
for (var i = 0; i < arra.length; i++) {
while(k!==arra[i]){
return false;
}
}
return true;
}
Well, this is really not very complicated. I have strong suspicion you didn't even try. What you do is that you pick the first value, save it in the variable, and then, within a for
loop, compare all subsequent values with the first one.
I intentionally didn't share any code. Find how for
is used and how variables are compared.
Simple one line solution, just compare it to an array filled with the first entry.
if(arr.join('') === Array(arr.length).fill(arr[0]).join(''))
this might work , you can use the comment out code as well that also woks well with the given scenerio.
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();
Another way with delimited size and organized list:
array1 = [1,2,3]; array2 = [1,2,3];
function isEqual(){
return array1.toString()==array2.toString();
}
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']));
And you are DONE !
In PHP, there is a solution very simple, one line method :
(count(array_count_values($array)) == 1)
For example :
$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
That's all.
Edit: Be a Red ninja:
!!array.reduce(function(a, b){ return (a === b) ? a : NaN; });
Results:
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"
Warning:
var array = [] => result: TypeError thrown
This is because we do not pass an initialValue. So, you may wish to check array.length
first.
If you're already using underscore.js, then here's another option using _.uniq
:
function allEqual(arr) {
return _.uniq(arr).length === 1;
}
_.uniq
returns a duplicate-free version of the array. If all the values are the same, then the length will be 1.
As mentioned in the comments, given that you may expect an empty array to return true
, then you should also check for that case:
function allEqual(arr) {
return arr.length === 0 || _.uniq(arr).length === 1;
}
You can use Array.every
if supported:
var equals = array.every(function(value, index, array){
return value === array[0];
});
Alternatives approach of a loop could be something like sort
var temp = array.slice(0).sort();
var equals = temp[0] === temp[temp.length - 1];
Or, if the items are like the question, something dirty like:
var equals = array.join('').split(array[0]).join('').length === 0;
Also works.
I think the simplest way to do this is to create a loop to compare the each value to the next. As long as there is a break in the "chain" then it would return false. If the first is equal to the second, the second equal to the third and so on, then we can conclude that all elements of the array are equal to each other.
given an array data[], then you can use:
for(x=0;x<data.length - 1;x++){
if (data[x] != data[x+1]){
isEqual = false;
}
}
alert("All elements are equal is " + isEqual);
You can use this:
function same(a) {
if (!a.length) return true;
return !a.filter(function (e) {
return e !== a[0];
}).length;
}
The function first checks whether the array is empty. If it is it's values are equals.. Otherwise it filter the array and takes all elements which are different from the first one. If there are no such values => the array contains only equal elements otherwise it doesn't.
The accepted answer worked great but I wanted to add a tiny bit. It didn't work for me to use ===
because I was comparing arrays of arrays of objects, however throughout my app I've been using the fast-deep-equal package which I highly recommend. With that, my code looks like this:
let areAllEqual = arrs.every((val, i, arr) => equal(val, arr[0]) );
and my data looks like this:
[
[
{
"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
}
]
]
Another interesting way when you use ES6 arrow function syntax:
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
And when you don't want to reuse the variable for array (x):
!['a', 'a', 'a', 'a'].filter((e,i,a)=>e!==a[0])[0] // true
IMO previous poster who used array.every(...) has the cleanest solution.
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; }
}
}
Now you can make use of sets to do that easily.
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);
You can convert array to a Set and check its size
In case of primitive array entries, i.e. number
, string
:
const isArrayWithEqualEntries = array => new Set(array).size === 1
In case of array of objects with some field to be tested for equivalence, say id
:
const mapper = ({id}) => id
const isArrayWithEqualEntries = array => new Set(array.map(mapper)).size === 1
You could use a for loop:
function isEqual(arr) {
var first = arr[0];
for (let i = 1; i < arr.length; i++) {
if (first !== arr[i]) {
return false;
}
}
return true;
}
©2020 All rights reserved.