I am having trouble understanding how I am mean't to find the getLength() of an iterable in my homework. The class is supposed to be a "toolkit" with useful methods for working on iterables and iterators.
/** Computes the length of an Iterable.
The length of an Iterable is the total number of entries it returns.
public static <T> int getLength(Iterable<T> iterable)
{
int numEntries = 0;
while(iterable.hasNext()) {
numEntries ;
iterable.next();
}
return numEntries;
}
This is what I currently have but I am getting this
Toolkit.java:30: error: cannot find symbol
while(iterable.hasNext()) {
^
symbol: method hasNext()
location: variable iterable of type Iterable<T>
where T is a type-variable:
T extends Object declared in method <T>getLength(Iterable<T>)
CodePudding user response:
This conceptually doesn't work. The concept of an Iterable
is solely that you can ask it to make iterators. It is the iterator that has the whole hasNext
and next
thing going on. Iterables are not guaranteed to return the same iterator everytime you ask for an iterator; you may call iterator()
and see 500 items, and then call it again and see 512. You have no particular guarantees, therefore, 'ask for the length of an iterable' is not answerable. For some specific known iterables, such as ArrayList
, you can answer the question and it'll be easy to do so, but there are iterables for which you cannot do this. Various iterables can only be asked for an iterator()
once, for example, anything representing a streaming concept (let's say your iterable is a firehose of all telegram messages sent to a telegram channel).
In other words, this is silly homework; whomever gave it does not fully understand what these concepts represent. This code will work for some iterables, but will fail for many others, either invalidating the ability to iterate through it after calling this, or crashing, or giving the wrong answer - it's exactly what you wrote, except, make an iterator first. While we're at it, lets get rid of that useless <T>
here, we don't need it:
public static int getLength(Iterable<?> iterable) {
int numEntries = 0;
var iterator = iterable.iterator();
while(iterator.hasNext()) {
numEntries ;
iterator.next();
}
return numEntries;
}
However, given that this doesn't actually 'work', I'd write something quite different:
public static int getLength(Iterable<?> iterable) throws IllegalArgumentException {
if (iterable instanceof Collection<?>) return ((Collection<?>) iterable).size();
throw new IllegalArgumentException("I don't know how to obtain the size for an iterable of type " iterable.getClass());
}
Really, the error in the whole setup is the argument. It should have been Collection<?>
all along. Almost all iterables you will ever meet implement Collection
- the main difference between Iterable and Collection is in fact that you can ask a collection how large it is. Iterable exists specifically because it represents a type where 'can I know how large you are' is not a required ability. Further highlighting how very silly this homework is.
Feel free to direct your teacher to this answer. If it's a general tutorial or book, toss it and get another one.
CodePudding user response:
Try this:
public static int size(`Iterable` data) {
if (data instanceof Collection) {
return ((Collection<?>) data).size();
}
int counter = 0;
for (Object i : data) {
counter ;
}
return counter;
}