Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Contains method for Iterable and Iterator?

Is there a simple method to check if an element is contained in an iterable or iterator, analogous to the Collection.contains(Object o) method?

I.e. instead of having to write:

Iterable<String> data = getData();
for (final String name : data) {
    if (name.equals(myName)) {
        return true;
    }
}

I would like to write:

Iterable<String> data = getData(); 
if (Collections.contains(data, myName)) {
    return true;
}

I'm really surprised there is no such thing.

like image 999
Roland Avatar asked Oct 27 '14 14:10

Roland


People also ask

What are the 2 methods that an iterator needs to implement?

Any class implementing the Iterator interface needs to override the hasNext() and next() methods provided by the Iterator interface. The hasNext() method returns true if the iteration has more elements, and the next() method returns the next element in the iteration.

How iterator and iterable are related?

An Iterable is basically an object that any user can iterate over. An Iterator is also an object that helps a user in iterating over another object (that is iterable). We can generate an iterator when we pass the object to the iter() method. We use the __next__() method for iterating.

What is iterable and iterator in Java?

An Iterable is a simple representation of a series of elements that can be iterated over. It does not have any iteration state such as a "current element". Instead, it has one method that produces an Iterator . An Iterator is the object with iteration state.


3 Answers

In Java 8, you can turn the Iterable into a Stream and use anyMatch on it:

String myName = ... ;
Iterable<String> data = getData();

return StreamSupport.stream(data.spliterator(), false)
                    .anyMatch(name -> myName.equals(name));

or using a method reference,

return StreamSupport.stream(data.spliterator(), false)
                    .anyMatch(myName::equals);
like image 56
Stuart Marks Avatar answered Oct 01 '22 04:10

Stuart Marks


Guava has the functions Iterables.contains and Iterators.contains which do what you want. You can look at the source to see how to implement them yourself.

like image 25
MikeFHay Avatar answered Oct 01 '22 04:10

MikeFHay


An iterator is a sort of cursor which can be moved over the elements of any collection of elements. So its inner state is mainly the pointer to the current element. If you would try to find out whether it "contains" a certain element you would have to move the cursor and therefore modify the inner state. Modifying the state by simply asking a question is surely a bad thing to do.

That is even the problem with the mentioned Guava. It will modify the iterator object by simply calling the contains method.

An iterable on the other hand is simply an interface telling the compiler that there is something to iterate over. In most cases the iterable object will be the collection itself. If you would add methods like "contains" to the interface Iterable you would get a (simplified) version of the Collection interface - which already exists. So there is no need for that.

If you are stuck in your code at some place where you have a reference to an iterable but need functionality of a collection you should think about refactoring your code. Either you should use the interface collection consistently or ask yourself why you should better not call collection methods at this point. So your problem is most probably a result of a suboptimal code design.

On the other hand I would consider it to be a strange thing to use Iterable as type for parameters or variables anyway. Technically you can do this but I think it is meant to be used in loops only.

like image 45
Wolf S Avatar answered Oct 02 '22 04:10

Wolf S