6
$\begingroup$

I have an array arr with n entries. Now I want to check whether

arr[[1]]==arr[[2]]&&arr[[2]]==arr[[3]]&&...arr[[n-1]]==arr[[n]]

Of course I could use a for-loop, like

arr = {0, 1, 0, 0};
IsConst = True;
For[i = 1, i <= Length[arr], i++,
  If[arr[[i]] != arr[[1]],
    IsConst = False;
    i = Length[arr];
  ];
];
Print[IsConst];

But that doesn't look too fast, so I wonder whether there is a faster way.

$\endgroup$
  • $\begingroup$ Union or DeleteDuplicates and then if the resulting list has length greater than 1 then the elements are not all the same (not constant in your terminology) $\endgroup$ – Mike Honeychurch Jan 12 '15 at 8:43
7
$\begingroup$

You can Apply (@@) Equal to your list:

constantQ = Equal@@#&;

constantQ @ {0,1,0,0}
(* False *)

or

constantQ2 = Max@#==Min@# &;
constantQ3 = Variance@#==0;
constantQ4 = Length@DeleteDuplicates@# == 1 &;

See also: SameQ

constantQ5 = SameQ @@ #&

Equal @@ {1, 1., 1}
(* True *)
SameQ @@ {1, 1., 1}
(* False *)

...

$\endgroup$
  • $\begingroup$ That looks nice, very interesting solutions (I should, at some point, really understand that kind of instructions you show). Thanks! $\endgroup$ – NicoDean Jan 12 '15 at 9:27
  • $\begingroup$ @NicoDean, my pleasure.. $\endgroup$ – kglr Jan 12 '15 at 9:32
4
$\begingroup$

Not sure why people don't like DeleteDuplicates :)

Length@DeleteDuplicates@arr > 1

for me this is faster than other methods (using V9 OS X tonight)

$\endgroup$
3
$\begingroup$
If[Length[Tally[arr]] == 1, IsConst = True, IsConst = False]
$\endgroup$
  • 3
    $\begingroup$ If is redundant here: IsConst = Length@Tally@arr == 1 $\endgroup$ – ybeltukov Jan 12 '15 at 9:37
3
$\begingroup$

Maybe the fastest is... just to compile the OP code

sameQ = Compile[{{arr, _Integer, 1}},
   Module[{IsConst = True, i},
    For[i = 1, i <= Length[arr], i++,
     If[arr[[i]] != arr[[1]],
      IsConst = False;
      Break[];
      ]];
    IsConst], CompilationTarget -> "C", "RuntimeOptions" -> "Speed"];

arr = ConstantArray[1, 10000000];
arr[[-1]] = 0;

sameQ[arr] // AbsoluteTiming
(* {0.027877, False} *)

constantQ4@arr // AbsoluteTiming (* fastest kguler's test *)
(* {0.062203, False} *)
$\endgroup$
  • $\begingroup$ Oh wow. That's exactly why I love SE :D $\endgroup$ – NicoDean Jan 12 '15 at 10:25
  • 2
    $\begingroup$ One of these days I really should install a C compiler... $\endgroup$ – Mr.Wizard Jan 12 '15 at 10:57
2
$\begingroup$

This problem is in a manner an converse of How do you check if there are any equal arguments(even sublist) in a list? and is related to How do I check if any element in a list is positive? As with both of those there is a choice in approach of either scanning the entire light with a fast, vectorized operation, or providing for an early-exit behavior. Which one is desirable will depend on the most commonly tested expression form. Please review my answer to the second linked question for examples.

Using Tally or Max and Min are examples of methods that scan the entire list without the possibility of an early exist.

The length of the list can also affect the performance of the methods used. For example, as noted here UnsameQ works well on short lists (few arguments) but not on long ones. That doesn't appear to be the case with Equal and SameQ however so both of those are good general methods for your problem, and provide early exist behavior. You can choose between numeric and structural equivalence. kguler already showed these but repeated for completeness:

Equal @@ {1, 1, 1, 1}
SameQ @@ {1, 1, 1, 1}
True
True
Equal @@ {1, 1, 2, 1}
SameQ @@ {1, 1, 2, 1}
False
False
Equal @@ {1, 1, 1.0, 1}
SameQ @@ {1, 1, 1.0, 1}
True
False

To bring a unique method to this answer we can also use pattern matching for structural equivalence:

MatchQ[{1, 1, 1, 1}, {x_ ..}]
MatchQ[{1, 1, 2, 1}, {x_ ..}]
True

False

By naming the Pattern (x_) we restrict it to matching a particular expression. See:

$\endgroup$
  • 1
    $\begingroup$ w.r.t. to timings, users should be reminded that Apply will unpack. Therefore MatchQ or checking the length of a deleted duplicates list may well be better options for packed arrays of larger length $\endgroup$ – Mike Honeychurch Jan 12 '15 at 10:04
  • $\begingroup$ @Mike Indeed. The issue of unpacking is mentioned in my answer to "How do I check if any element in a list is positive?" which I intend for people to read. I chose not to repeat myself here but instead direct readers to the earlier questions. $\endgroup$ – Mr.Wizard Jan 12 '15 at 10:10
  • $\begingroup$ no worries. Am watching the cricket, having a beer, and reading this ...am not a multi tasker! $\endgroup$ – Mike Honeychurch Jan 12 '15 at 10:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.