Get size of an Iterable in Java - java

I need to figure out the number of elements in an Iterable in Java.
I know I can do this:
Iterable values = ...
it = values.iterator();
while (it.hasNext()) {
it.next();
sum++;
}
I could also do something like this, because I do not need the objects in the Iterable any further:
it = values.iterator();
while (it.hasNext()) {
it.remove();
sum++;
}
A small scale benchmark did not show much performance difference, any comments or other ideas for this problem?

TL;DR: Use the utility method Iterables.size(Iterable) of the great Guava library.
Of your two code snippets, you should use the first one, because the second one will remove all elements from values, so it is empty afterwards. Changing a data structure for a simple query like its size is very unexpected.
For performance, this depends on your data structure. If it is for example in fact an ArrayList, removing elements from the beginning (what your second method is doing) is very slow (calculating the size becomes O(n*n) instead of O(n) as it should be).
In general, if there is the chance that values is actually a Collection and not only an Iterable, check this and call size() in case:
if (values instanceof Collection<?>) {
return ((Collection<?>)values).size();
}
// use Iterator here...
The call to size() will usually be much faster than counting the number of elements, and this trick is exactly what Iterables.size(Iterable) of Guava does for you.

If you are working with java 8 you may use:
Iterable values = ...
long size = values.spliterator().getExactSizeIfKnown();
it will only work if the iterable source has a determined size. Most Spliterators for Collections will, but you may have issues if it comes from a HashSetor ResultSetfor instance.
You can check the javadoc here.
If Java 8 is not an option, or if you don't know where the iterable comes from, you can use the same approach as guava:
if (iterable instanceof Collection) {
return ((Collection<?>) iterable).size();
} else {
int count = 0;
Iterator iterator = iterable.iterator();
while(iterator.hasNext()) {
iterator.next();
count++;
}
return count;
}

This is perhaps a bit late, but may help someone. I come across similar issue with Iterable in my codebase and solution was to use for each without explicitly calling values.iterator();.
int size = 0;
for(T value : values) {
size++;
}

You can cast your iterable to a list then use .size() on it.
Lists.newArrayList(iterable).size();
For the sake of clarity, the above method will require the following import:
import com.google.common.collect.Lists;

Strictly speaking, Iterable does not have size. Think data structure like a cycle.
And think about following Iterable instance, No size:
new Iterable(){
#Override public Iterator iterator() {
return new Iterator(){
#Override
public boolean hasNext() {
return isExternalSystemAvailble();
}
#Override
public Object next() {
return fetchDataFromExternalSystem();
}};
}};

java 8 and above
StreamSupport.stream(data.spliterator(), false).count();

I would go for it.next() for the simple reason that next() is guaranteed to be implemented, while remove() is an optional operation.
E next()
Returns the next element in the iteration.
void remove()
Removes from the underlying collection the last element returned by the iterator (optional operation).

As for me, these are just different methods. The first one leaves the object you're iterating on unchanged, while the seconds leaves it empty.
The question is what do you want to do.
The complexity of removing is based on implementation of your iterable object.
If you're using Collections - just obtain the size like was proposed by Kazekage Gaara - its usually the best approach performance wise.

Why don't you simply use the size() method on your Collection to get the number of elements?
Iterator is just meant to iterate,nothing else.

Instead of using loops and counting each element or using and third party library we can simply typecast the iterable in ArrayList and get its size.
((ArrayList) iterable).size();

Related

Adavantages of HashSet over ArrayList and vice versa

I have a doubt regarding data structures in Java. While solving a typical hashing problem in Java, I was using the HashSet data structure, which worked fine until there were duplicate objects (object contents). Since HashSet does not support insert of duplicates, my logic was failing.
I replaced the hashset with the typical Arraylist since the methods of hashset such as .add(), .contains(), .remove() are supported in both, and my logic worked perfectly then.
But does this necessarily mean ArrayList is the logical choice over Hashset when duplicates are involved? There should be some time complexity advantages of Hashset over ArrayList right? Can someone please provide me some insight regarding this?
EDIT: What would be the ideal data structure when you want to do hashing when duplicates are involved. I mean when the duplicates should not be ignored and should be inserted.
It's not clear what you mean by a "hashing problem," but maybe you're looking for a multiset. From the Guava docs:
A collection that supports order-independent equality, like Set, but may have duplicate elements. A multiset is also sometimes called a bag.
Elements of a multiset that are equal to one another are referred to as occurrences of the same single element. The total number of occurrences of an element in a multiset is called the count of that element (the terms "frequency" and "multiplicity" are equivalent, but not used in this API).
No such thing exists in the JDK.
When you use a HashMap it replaces the original value with the new duplicate.
When you use a HashSet, subsequent duplicates are ignored (not inserted).
When you use an ArrayList, it simply adds the duplicate to the end of the list
It all depended on what you need given your requirements.
ArrayList is not the logical choice if you don't want duplicates. Different tools for different use cases.
You would use a Set in areas where duplicates wouldn't make sense, for example, a set of students. A List allows duplicates.
If you specifically need a HashSet that handles duplicates, a HashMap will be able to do the job. If you just need a count of the number of objects added (with quick lookup/etc), a HashMap<T,Integer> will be ideal, where T is the type of your object. If you actually need to keep references to the duplicate objects you've added, go with HashMap<T, List<T>>. That way you can look up by using HashMap's .containsKey(T t), and iterate through all of the similarly hashing objects in the resulting list. So for example, you could create this class:
public class HashSetWithDuplicates<T> {
private HashMap<T, List<T>> entries;
private int size;
public HashSetWithDuplicates(){
entries = new HashMap<>();
size = 0;
}
public HashSetWithDuplicates(Collection<? extends T> col){
this();
for(T t : col){
add(t);
}
}
public boolean contains(T t){
return entries.containsKey(t);
}
public List<T> get(T t){
return entries.get(t);
}
public void add(T t){
if (!contains(t)) entries.put(t, new ArrayList<>());
entries.get(t).add(t);
size++;
}
public void remove(T t){
if (!contains(t)) return;
entries.get(t).remove(t);
if(entries.get(t).isEmpty()) entries.remove(t);
size--;
}
public int size(){
return size;
}
public boolean isEmpty(){
return size() == 0;
}
}
Add functionality to your needs.

Modifying each item of a List in java

I'm just starting to work with lists in java. I'm wondering what the recommended method to modify each element of a list would be?
I've been able to get it done with both the following methods, but they both seem fairly unelegant. Is there any better way to get this done in java? And is any of the below methods recommended over the other, or are both on the same level?
//Modifying with foreach
for (String each : list)
{
list.set(list.indexOf(each), each+ " blah");
}
//Modifying with for
for (ListIterator<String> i = list.listIterator(); i.hasNext(); i.next())
{
i.next();
list.set(i.nextIndex()-1, i.previous() + " blah yadda");
}
The second version would be better. Internally they are the same in the end, but the second actually allows you to modify the list, while the first one will throw a ConcurrentModificationException.
But then you are using the Iterator in a wrong way. Here is how you do it correctly:
for (final ListIterator<String> i = list.listIterator(); i.hasNext();) {
final String element = i.next();
i.set(element + "yaddayadda");
}
The iterator is the one that needs to modify the list as it is the only one that knows how to do that properly without getting confused about the list elements and order.
Edit: Because I see this in all comments and the other answers:
Why you should not use list.get, list.set and list.size in a loop
There are many collections in the Java collections framework, each on optimized for specific needs. Many people use the ArrayList, which internally uses an array. This is fine as long as the amount of elements does not change much over time and has the special benefit that get, set and size are constant time operations on this specific type of list.
There are however other list types, where this is not true. For example if you have a list that constantly grows and/or shrinks, it is much better to use a LinkedList, because in contrast to the ArrayList add(element) is a constant time operation, but add(index, element), get(index) and remove(index) are not!
To get the position of the specific index, the list needs to be traversed from the first/last till the specific element is found. So if you do that in a loop, this is equal to the following pseudo-code:
for (int index = 0; index < list.size(); ++index) {
Element e = get( (for(int i = 0; i < size; ++i) { if (i == index) return element; else element = nextElement(); }) );
}
The Iterator is an abstract way to traverse a list and therefore it can ensure that the traversal is done in an optimal way for each list. Test show that there is little time difference between using an iterator and get(i) for an ArrayList, but a huge time difference (in favor for the iterator) on a LinkedList.
EDIT: If you know that size(), get(index) and set(index, value) are all constant time operations for the operations you're using (e.g. for ArrayList), I would personally just skip the iterators in this case:
for (int i = 0; i < list.size(); i++) {
list.set(i, list.get(i) + " blah");
}
Your first approach is inefficient and potentially incorrect (as indexOf may return the wrong value - it will return the first match). Your second approach is very confusing - the fact that you call next() twice and previous once makes it hard to understand in my view.
Any approach using List.set(index, value) will be inefficient for a list which doesn't have constant time indexed write access, of course. As TwoThe noted, using ListIterator.set(value) is much better. TwoThe's approach of using a ListIterator is a better general purpose approach.
That said, another alternative in many cases would be to change your design to project one list to another instead - either as a view or materially. When you're not changing the list, you don't need to worry about it.
Internally there in Iterator for for-each implementation. So there is no deference between these two cases. But if you trying to modify element it will throws ConcurrentModificationException.
I got mine working this way
String desiredInvoice="abc-123";
long desiredAmount=1500;
for (ListIterator<MyPurchase> it = input.getMyPurchaseList().listIterator(); it.hasNext();) {
MyPurchase item = it.next();
if (item.getInvoiceNo().equalsIgnoreCase(desiredInvoice)) {
item.setPaymentAmount(desiredAmount);
it.set(item);
break;
}
}

Can I subclass "standard" arraylist iterator?

I need to iterate all the elements of ArrayList except the last one. So I want to create such iterator. But I don't what to implement the whole iterator, I need to override only the hasNext() method, so I would like to subclass a "standard" iterator. Is there any way to do that?
I think the better way to do that rather than overriding the default iterator is to iterate the ArrayList on your own. An ArrayListhas a couple of method defined that can help you accomplish the task: get(int) and size().
Everything you have to do is to get the total number of elements in the ArrayList(with size()) and then loop through the elements accessing each element directly in each iteration using the get() method. Your code would look something like this:
for(int i = 0; i < myList.size() - 1; i++){
element = myList.get(i);
//do something
}
Now with this principle in mind, you may create your own class to iterate the ArrayList.
It would be odd to modify the iterator to perform this traversal. The obvious thing to do is to write the "algorithm" as you want it:
public static <T> void eachExceptLast(List<? extends T> list, Operation<T> op) {
Iterator<T> iter = list.iterator();
if (!iter.hasNext()) {
return;
}
T item = iter.next();
while (iter.hasNext()) {
op.run(item);
item = iter.next();
}
}
(Or use an index assuming a RandomAccess list.)
However, there's a much better way of doing this. list.subList(0, list.size()-1) (for a non-empty list) will return a view of the original list less the last element. It doesn't do a copy, and you can even use Iterator.remove.
You can create a class that implements either the Iterator or ListIterator interfaces and then override the hasNext() method .

Is it possible to use the values method for a HashMap if the values are ArrayLists?

I'm stuck trying to get something to work in an assignment. I have a HashMap<Integer, ArrayList<Object>> called sharedLocks and I want to check whether a certain value can be found in any ArrayList in the HashMap.
The following code obviously wouldn't work because Object[] can't be cast to ArrayList[], but it is a demonstration of the general functionality that I want.
ArrayList[] values = (ArrayList[]) sharedLocks.values().toArray();
boolean valueExists = false;
for (int i = 0; i < values.length; i++) {
if (values[i].contains(accessedObject)) {
valueExists = true;
}
}
Is there a way for me to check every ArrayList in the HashMap for a certain value? I'm not sure how to use the values method for HashMaps in this case.
Any help would be much appreciated.
HashMap.values() returns a Collection. You can iterate through the collection without having to convert it to an array (or list).
for (ArrayList<Object> value : sharedLocks.values()) {
...
}
A HashMap is a bit special, in that it doesn't really have an index to go by at all...
What you want to do, is turn the HashMap into a collection first, and then iterate through the collection with an iterator.
Whenever you get hold of an ArrayList in the HashMap, you cycle through every element in the arrayList, and then you jump out if you find it :)
Use the toArray method which takes an array as an argument.
This uses the array you specify to fill the data, and maintains the typing so you don't need to typecast. Additionally, you should keep the generic <Object> in the definition.
ArrayList<Object>[] values =
sharedLocks.values().toArray(new ArrayList<Object>[sharedLocks.size()]);
One more thing to consider is if multiple threads can modify this HashMap. In this case, you will want to synchronize this line of code to the HashMap and make sure all modifications are also synchronized. This will make sure that other threads won't modify the contents between the .size() call and the .toArray() call, which is possible.
You dont need arrays:
boolean valueExists = false;
for (ArrayList<Object> value : sharedLocks.values()) {
if (value.contains(accessedObject)) {
valueExists = true;
break;
}
}
Why not just iterate through all the values in the map:
for (ArrayList<Object> list : sharedLocks) {
if (list.contains(accessedObject)) {
// ...
}
}
heres a link to an example of iterating though a hash map. Use this to pull out each arraylist and in turn extend this to then search each element of the array list for the given entry.
http://www.java-examples.com/iterate-through-values-java-hashmap-example
you will need to use a nested foreach loop.
foreach(every element in the hashmap) {
foreach(every element in arraylist) {
// do comparision
}
}
you might just get away with a foreach loop and a keyExists() call or something within it. I cannot recall the API off the top of my head.

Iterator has .next() - is there a way to get the previous element instead of the next one?

I have an Iterator that I use on a HashMap, and I save and load the iterator.
is there a way to get the previous key in the HashMap with Iterator? (java.util.Iterator)
Update
I save it as an attribute in a Red5 connection and then load it back to continue working where i stopped.
Another update
I'm iterating through the keyset of the HashMap
You can use ListIterator instead of Iterator.
ListIterator has previous() and hasPrevious() methods.
Not directly, as others pointed out, but if you e.g. need to access one previous element you could easily save that in a separate variable.
T previous = null;
for (Iterator<T> i = map.keySet().iterator(); i.hasNext();) {
T element = i.next();
// Do something with "element" and "previous" (if not null)
previous = element;
}
It sounds like you want the array semantics more akin to a ListIterator rather than those provided by the Iterator interface. The easiest way to acquire such a thing is likely to construct a list ( from the key-set (LinkedList<K> keyList = new LinkedList<K>(map.keySet())), then use a ListIterator manually instead of a regular Iterator or foreach.
For very simple cases of needing to remember consecutive items, the simplest way to handle this is to store the previous Key in a local variable and update it at the end of the loop.
No, an Iterator<E> defines only 3 methods:
boolean hasNext()
E next()
void remove()
You can of course implement your own iterator.
As others have said, you only access an element using next(). However it's sort of a matter of terminology. Once you call next() this is the current element.
Unless the problem is you need to see two consecutive items in the collection each iteration, in which case a simple variable would seem easiest.
Although Set doesn't provide a method for a reverse iterator, Deque does. You can use descendingIterator() for an iterator in reverse order and iterator(), for an iterator in forwards order.
(You can create a Deque from a Set via Deque<T> deque = new LinkedList<T>(set), where set is your Set and T the generic type you're using.)
Ultimately Iterators are not fully suited for your task.
Why not create a List from your Set (via, eg, List list = new LinkedList(set)) and iterate by using a standard indexed for-loop? That way you know the previous element is at i - 1.
using iterator, No you dont have an option to get a previous key value. it has only hasNext() and next() methods.
No, you can't. The Iterator interface has no method to get the previous element.
But what you can do is - a little bit rubbish- creating a List<Entry<Integer, YourObjectType>> where the Integer-value represents the hash-code of the key-object. Then you can do something like this:
for (int i = 0; i < list.size(); i++)
{
YourObjectType current = list.get(i).getValue();
YourObjectType previous = (i == 0 ? null : list.get(i - 1).getValue());
// Do whatever you want
}
I know this is very rubbish, but it is possible
Make your own Iterator:
public class EnhancedIterator<E> implements Iterator<E>{
private List<E> list;
private int indexSelected=-1;
public EnhancedIterator(List<E> list){
this.list=list;
}
#Override
public boolean hasNext() {
return indexSelected<list.size()-1;
}
#Override
public E next() {
indexSelected++;
return current();
}
#Override
public void remove() {
list.remove(indexSelected);
}
public void remove(int i){
list.remove(i);
if(i<indexSelected){
indexSelected--;
}
}
public E previous(){
indexSelected--;
return current();
}
public E current(){
return list.get(indexSelected);
}
public E get(int i){
return list.get(i);
}
}

Categories