Java all determine elements are same in a list
Asked Answered
C

3

44

I am trying to determine to see if all elements in a list are same. such as:

(10,10,10,10,10) --> true
(10,10,20,30,30) --> false

I know hashset might be helpful, but i don't know how to write in java.

this is the one I've tried, but didn't work:

public static boolean allElementsTheSame(List<String> templist) 
{

    boolean flag = true;
    String first = templist.get(0);

    for (int i = 1; i< templist.size() && flag; i++)
    {
        if(templist.get(i) != first) flag = false;
    }

    return true;
}
Campbellite answered 26/3, 2015 at 20:47 Comment(3)
if all elements are the same, they must all be equal to first element (unless list is empty)... just iterate and check itKilbride
You need return flag; in your code at the very least.Limey
You are currently always returning true in the last line.Placative
R
108

Using the Stream API (Java 8+)

boolean allEqual = list.stream().distinct().limit(2).count() <= 1

or

boolean allEqual = list.isEmpty() || list.stream().allMatch(list.get(0)::equals);

Using a Set:

boolean allEqual = new HashSet<String>(tempList).size() <= 1;

Using a loop:

boolean allEqual = true;
for (String s : list) {
    if(!s.equals(list.get(0)))
        allEqual = false;
}

Issues with OP's code

Two issues with your code:

  • Since you're comparing Strings you should use !templist.get(i).equals(first) instead of !=.

  • You have return true; while it should be return flag;

Apart from that, your algorithm is sound, but you could get away without the flag by doing:

String first = templist.get(0);
for (int i = 1; i < templist.size(); i++) {
    if(!templist.get(i).equals(first))
        return false;
}
return true;

Or even

String first = templist.get(0);
for (String s : templist) {
    if(!s.equals(first))
        return false;
}
return true;
Roar answered 26/3, 2015 at 20:50 Comment(10)
@PM77-1, for a list of (1, 2, 3, 4, 5), the limit(2) will make sure it terminates early after (1, 2).Roar
I understand that. The question is whether count() is expensive enough to outweigh the overhead of the extra operation.Limey
It makes a difference for large lists with many unique elements. Consider for instance ("0000000001", "000000002", ..., "999999999"). It's obviously faster to look at the two first elements, then having to count how many unique elements there are in total.Roar
Unfortunately the solution with the allSame method using a HashSet was deleted... nevertheless a little (non representative) performance test with 1_000_000 strings with 1.) 3rd value differs from all others: for-loop:0ms, set:31ms, stream:47ms, 2.) with all values equal: for-loop:18ms, set:32ms, stream:85ms, so the Set solution is not the worst; the accepted stream solution seems to be the least performant one and the ordinary for-loop wins; conclusion: it's always good to measure performance...Raeraeann
@tomse, micro benchmarking on the JVM is notoriously difficult. The fact that your measurements are below a 10th of a second tells me these figures aren't very reliable.Roar
@Roar OK, this is not a representative example for all use cases, but even if the absolut time might not be very useful it shows the differences between the different algorithms - or not?Raeraeann
What I'm saying is that without a decent JMH test, proper JVM warm up or JVM startup arguments, I don't think you can make many conclusions based on your figures.Roar
@PM77-1 It's not about count(). What is important here is that the entire sequence will terminate, once two distinct elements are found. The way the Streams library is designed is that .distinct() will not iterate over the entire stream, creating a new stream. Instead it's just a decorator over the existing stream. The same goes for .limit(2). The list is 'terminated' when .count() is called and that's the moment where the actual iterating is done, where the final stream (created by limit) will simply stop once it has found two elements. Regardless of the size of your original list.Grivation
Good suggestions. I happened to need the actual "thing" that was the same in all the list, so here is the (untested) code (so I won't forget later and to help others): Optional<Foo> commonFoo = fooList.stream().findAny().flatMap(foo -> fooList.stream().allMatch(foo::equals) ? Optional.of(foo) : Optional.empty())Shir
In your second stream example, you can insert .skip(1) because comparing the first element to itself is unnecessaryLour
P
8

The frequency of a value in a list will be the same as the size of the list.

boolean allEqual = Collections.frequency(templist, list.get(0)) == templist.size()

Pouncey answered 28/7, 2017 at 0:1 Comment(0)
J
6

This is a great use case for the Stream.allMatch() method:

boolean allMatch(Predicate predicate)

Returns whether all elements of this stream match the provided predicate.

You can even make your method generic, so it can be used with lists of any type:

static boolean allElementsTheSame(List<?> templist) {
    return templist.stream().allMatch(e -> e.equals(templist.get(0)));
}
John answered 26/3, 2015 at 21:38 Comment(2)
Why the whole if-statement? Just the second return statement should do I believe.Roar
Yes, you are right. I was trying to prevent an IndexOutOfBoundsException on get(0), but I see it wouldn't happen as get(0) won't be executed when the list is empty. I updated the answer. Thank you for noticing it.John

© 2022 - 2024 — McMap. All rights reserved.