4

I want to create a function to iterate over multiple lists. Now I know these lists have exactly the same size (and they can have different types too), for example:

List<Integer> list1 = getList1();
List<String> list2 = getList2();
List<Long> list3 = getList3();
list1.size() == list2.size(); // returns true
list2.size() == list3.size(); // returns true

And I want to be able to call a function which takes 3 elements at the same slice in each of these lists so for exemple:

int calculate(int elemList1, String elemList2, long elemList3) {...}

// iterator over the lists in parallel {
    int ret = calculate(elemList1, elemList2, elemList3);
// }

I would like to do the equivalent of what I saw discussed in guava here but doesn't look implemented yet: http://code.google.com/p/guava-libraries/issues/detail?id=677

They talk about doing Iterators.interleave or Iterators.zip and I would like to do something similar but I haven't been able to, so can someone please help me a bit? Thanks!

I would prefer to not have to get the size of one list and iterate over them by index, because in the future i can have lists of different sizes so i would like to use only 1 way to do this.

darkuzul
  • 63
  • 1
  • 1
  • 11
  • Are you trying to iterate over multiple lists at the same time using a zip technique, or are you actually trying to multithread here? – Platinum Azure Jan 25 '13 at 00:47
  • IIRC this was never decided upon, hence never implemented. I faked it by creating a multimap keyed by index and adding each collection's items (because I couldn't guarantee the collections were something like an ArrayList, so get(n) wasn't deterministic). – Dave Newton Jan 25 '13 at 00:48
  • no I just want to iterate at the same time using something like zip like i explained i would like to do something similar to what they discussed at guava. – darkuzul Jan 25 '13 at 00:49
  • The Guava solution looks like it has logic to deal with the lists having different sizes, which you don't need. – Rob Jan 25 '13 at 00:49

3 Answers3

12

A compound Iterator might be a cool idea, e.g.:

Iterator<Array<?>> compoundIterator = createIterator(List1, List2, List3);

Then inside the implementation, you would create iterators for each of the lists, then loop through the items and put them into an array, then your consumption of that stuff would look something like:

while (compoundIterator.hasElements()){
    Array[] elements = compountIterator.nextElement();
    calculate(elements[0], elements[1], elements[2]);
}

What's nice about this solution is you are hiding all those details about whether one list ran out or not (of course you have to decide what you want to do if one does, but that could be wrapped inside as well).

Rob
  • 11,446
  • 7
  • 39
  • 57
  • I like this solution thanks I will do this ! Is it hrd to create an iterator implementation? Do i need to do something to reward your answer? – darkuzul Jan 25 '13 at 01:06
  • Just click the checkbox to reward. No, doing your own iterator is easy, and a good exercise. – Rob Jan 25 '13 at 01:07
  • Sure. Post again if you have an issue, but you are just supplying implementations of two methods that you are going to be delegating. :) – Rob Jan 25 '13 at 01:09
  • I'd prefer the simple solution you posted as your other answer. In this case you have to cast every array element to the correct type. I don't see the benefit of this approach. – Christoph Leiter Jan 25 '13 at 11:05
  • If you're going to provide input from Arrays, having casts is probably not a huge consideration. I am a hard core OO guy, I think you should use objects for everything, but that said, I see the value potentially of an aggregate iterator. Frankly, you could solve your objections by parameterizing the types, e.g. CompoundAggregator. Then there would be no casts (no you can't do a variable number of type arguments but, there's probably a limit to how many simultaneous things you want to handle). – Rob Jan 25 '13 at 14:24
  • The syntax in this answer is a little confusing. What is `Array`? Why is it `Array>`, then later `Array[]`? Did you mean `Object[]`? – Paul Bellora Jan 26 '13 at 23:49
  • If you are going to have different types as an Array, that's what it would look like. See the note about doing types through generics. – Rob Jan 27 '13 at 00:22
2

You can create a new thread and iterate your list there. Spawn multiple of this therad and you can iterate your list in parallel.

If you want to pass List of any template type, you can just specify your method parameter as List, although this might result in compiler warnings. Other thing you can try is pass the list as List<T extends Object> and do a runtime check of type T and action accordingly

However if by 'parallel' you are not referring to multithreading / concurrency -- instead just want to be able to iterate your 3 lists in one single loop, then something like this will do (warning code is rough example only -- not tested / complying with coding standard):

List list1 = ...
List list2 = ...
List list3 = ...

for(int i=0,j=0,k=0; i<list1.size() && j<list2.size() && k<list3.size(); ++i,++j,++k)
{
   Object elemOfList1 = list1.get(i);
   Object elemOfList2 = list2.get(j);
   Object elemOfList3 = list3.get(k);
   // do something here
}
gerrytan
  • 40,313
  • 9
  • 84
  • 99
  • but i need to apply a function for a slice of these lists (i edited my post to explain), i can't do that if i have to use threads or i have to make complicated logic to synchronize no? – darkuzul Jan 25 '13 at 00:45
  • In that case have a read at the new Java 7 Fork/Join feature, see if it can help you: http://docs.oracle.com/javase/tutorial/essential/concurrency/forkjoin.html – gerrytan Jan 25 '13 at 00:49
  • i don't see why i need threads for this, I would just need to iterate over lists in parallel to apply a function at each iteration, is there no way avoiding threads? – darkuzul Jan 25 '13 at 00:51
  • How do you do something in parallel without multiple threads? I don't think you can.. – gerrytan Jan 25 '13 at 00:54
  • the idea for guava.zip is exactly what i wanted to do but it doesn't seem to involve any thread. – darkuzul Jan 25 '13 at 00:56
1

I don't think you are really saying in parallel, since the values are being used to invoke a method. If you want the same elements from each list, concurrently skipping through different lists on different threads does you no good.

You just need to do a for loop and then call list1.get(i), list2.get(i), list3.get(i).

Rob
  • 11,446
  • 7
  • 39
  • 57
  • thanks you Rob i thought about this too, but i'd like to do more an iterator approach instead of having to call the lists by their index, i think the guava discussion is exactly what i would like to do but not implemented – darkuzul Jan 25 '13 at 00:52
  • As I said, that gives you the ability to see if you are at the end. You don't have that problem? – Rob Jan 25 '13 at 00:56
  • it works but in the future i can have lists of different size and i would like to be able to handle that too thanks. – darkuzul Jan 25 '13 at 00:57
  • Sure. The other thing that would be cool would be to possibly make your own Iterator that is an aggregator of other Iterators, and then returns an Array. I'll add that as another answer. – Rob Jan 25 '13 at 00:58
  • yes i think that's exactly what im looking for, thank you for your help. – darkuzul Jan 25 '13 at 00:59
  • What are you supposed to do when the lists have different sizes? If you just want to stop when you reach the end of the smallest list, you can just get the min of the sizes, then do a `for(int i = 0; i <= minSize; i++)` in your loop. – Etienne Neveu Jan 25 '13 at 01:12
  • Well, it is conceivable that you might have a situation where you have something like the int values can be zero when they run out.. ? Who knows. I think this is preferable if you don't want to worry about size. – Rob Jan 25 '13 at 01:14