In C++, I can use find_if with a predicate to find an element in a container. Is there something like that in Java? The contains method on collections uses equals and can not be parameterized.
You can use Predicate from Google Collections. Here is the tutorial and an example from it:
final Predicate<Car> expensiveCar = new Predicate<Car>() {
public boolean apply(Car car) {
return car.price > 50000;
}
}
List<Car> cars = Lists.newArrayList();
cars.add(new Car("Ford Taurus", 20000));
cars.add(new Car("Tesla", 90000));
cars.add(new Car("Toyota Camry", 25000));
cars.add(new Car("McClaren F1", 600000));
final List<Car> premiumCars =
Lists.immutableList(Iterables.filter(cars, expensiveCar));
You can also look at this thread: What is the best way to filter a Collection?
You can use CollectionUtils.select from Apache Commons.
For example, the following C++ code
bool isOdd (int i) {
return i % 2 != 0;
}
...
vector<int> myvector;
vector<int>::iterator it;
myvector.push_back(10);
myvector.push_back(25);
myvector.push_back(40);
myvector.push_back(55);
it = find_if (myvector.begin(), myvector.end(), isOdd);
cout << "The first odd value is " << *it << endl;
can be written in Java as,
List<Integer> myList = Arrays.asList(10, 25, 40, 55);
List<Integer> oddNums = (List<Integer>) CollectionUtils.select(myList,
new Predicate<Integer>() {
public boolean apply(Integer i) {
return i % 2 != 0;
}
}
);
System.out.println("The first odd value is "+oddNums.get(0));
Please note that, unlike in C++ example, this would create a new list of the elements satisfying the specified predicate.
EDIT :
As Matthew Flaschen has suggested in a comment below, CollectionUtils.find is even closer to what you need. So, with find, the above code can be rewritten as:
List<Integer> myList = Arrays.asList(10, 25, 40, 55);
Integer firstOdd = (Integer) CollectionUtils.find(myList,
new Predicate<Integer>() {
public boolean apply(Integer i) {
return i % 2 == 1;
}
}
);
System.out.println("The first odd value is "+firstOdd);
The problem is that using a method like find_if should make the code simpler to write and easier to read. However, IMHO Java does not lend itself to functional notation and most of the time it is clearer and simpler to just write a natural loop. i.e. the code is shorter and doesn't require knowledge of libraries most people don't use. If this functionality was built in and Java supported Closures (as
it appears Java 7 will) then using predicates and functional methods would make more sense.
One measure of complexity is to count the number of symbols (counting open/close brackets as one) Using this measure of complexity, most predicate based solutions have more symbols and are possibly more complex and difficult for developers to read/maintain.
In the example given by #Roman, there are 15 symbols. In the loop example, there are 10 symbols.
List<Car> premiumCars = new ArrayList();
for(Car car: cars)
if(car.price > 50000)
premiumCars.add(car);
In the example by #Mario Fuscom, there is 9 symbols, in the following example there is 9 symbols. However, no non-standard functions are required and anyone who knows Java can read/maintain it.
List peopleOver30 = new ArrayList();
for(Person person: people)
if(person.age > 30)
peopleOver30.add(person);
Taking the last example from #Rahul G - I hate Unicorns, there are 13 symbols. In the loop example, there are 8 symbols.
Integer firstOdd = null;
for(int i: myList)
if(i % 2 == 1) {
firstOdd = i;
break;
}
Functional programming may make more sense to you because that is your development background, but this doesn't mean it is the natural or simplest way to express this in Java. Java 7 may change this....
In Java 8, we have removeIf() which removes elements from the collections with certain Predicate. But we do not have something like find_if. But we can use stream API to achieve this.
List<Integer> list = Arrays.asList(20,35,50,654);
int result = list.stream().filter(i-> i%2!=0).findFirst().orElse(0).intValue();
System.out.println(result);
By using lambdaj you can easily filter a java collection in a very readable way. For example the following statement:
select(persons, having(on(Person.class).getAge(), greaterThan(30)));
selects all the persons in your list having more than 30 years.
Related
This question already has answers here:
How to short-circuit a reduce() operation on a Stream?
(4 answers)
Closed 3 years ago.
I have a Stream of Lists of which I want to get the entry with the least elements. I could of course do something like
Stream<List<T>> s = ...
s.min((e1, e2) -> e1.size() - e2.size());
But in a case like this, we know a lower bound for the minimum, since the size is non-negative. Meaning the moment a List of size 0 is found, we could actually stop, instead of running through the rest of the list too.
Can this be achieved in a decent way with Java Streams?
I would imagine it looking something like this, giving a comparator and a function which tells us when the current minimum is a global one:
s.boundedMin(
(e1, e2) -> e1.size() - e2.size(),
e -> e.size() == 0
)
I can't think of a way to implement this.
Of course I could just use an Iterable and use a loop with break-statement to get this, I just wondered if streams could get me there too.
Edit:
To make it a bit clearer. The Stream might or might not contain Lists of size 0. My issue is that min() will run through the whole stream, even if it already found a list of size 0 (which is already as small as it can ever get). So, what I'm looking for is an implementation of min which does not need to scan through the whole stream, by providing a lower bound for the minimum.
Edit2:
An equivalent iterative solution without streams would be
List<List<T>> s = ...
List<T> min = null;
for (List<T> l : s) {
if (min == null || min.size() > l.size())
min = l;
if (min.size() == 0) {
break;
}
}
Just for the fun of it:
static <T> int size(Stream<List<T>> st) {
class MinHolder implements Consumer<List<T>> {
private int min = Integer.MAX_VALUE;
public void accept(List<T> l) {
if (min > l.size()) {
min = l.size();
}
}
}
MinHolder holder = new MinHolder();
Spliterator<List<T>> sp = st.spliterator();
int elements = 0;
for (; sp.tryAdvance(holder) && holder.min > 0; ++elements) {
}
System.out.printf("took %s elements to find the min%n", elements);
return holder.min;
}
And a few test cases:
public static void main(String[] args) {
Stream<List<Integer>> st = Stream.of(List.of());
System.out.println(size(st));
st = Stream.empty();
System.out.println(size(st));
st = Stream.of(List.of(), List.of(1), List.of(1, 2), List.of(1, 2, 3));
System.out.println(size(st));
}
If you are not forced to use a Stream<List<T>> then don't; this conditional breaking is not something Streams were designed for and would be considered an abuse by many.
I'm currently learning Java and I'm interested in learning how to use the list foreach method rather than using a manually constructed for loop. I suspect they can perform the same.
My current code looks like this:
while(!this.cards.isEmpty()) {
for(int i = 0; i < this.table.GetPlayerCount() && !this.cards.isEmpty(); i++) {
DealOneCardToPlayer(this.table.players.get(i) ,this.cards.get(0));
this.cards.remove(0);
}
}
I suspect that there is a way to use something like this:
this.cards.foreach() { do suff }
but I haven't quite been able to nail down the syntax... can someone give me a quick hand?
I think you can do it by iterating over the indexes of the cards:
IntStream.range(0, this.cards.size()).forEach(idx -> {
DealOneCardToPlayer(
this.table.players.get(idx % this.table.GetPlayerCount()),
this.cards.get(idx));
});
Although this doesn't remove the cards as you go; if you really need this.cards to be empty after:
this.cards.clear();
If you want to limit the number of cards dealt out (e.g. you want to deal N cards to each player), the easiest way is to extract a sublist, and then just apply the same method above:
List<Card> cardsToDeal = this.cards.subList(0, numCardsToDeal);
IntStream.range(0, cardsToDeal.size()).forEach(idx -> {
DealOneCardToPlayer(
this.table.players.get(idx % this.table.GetPlayerCount()),
cardsToDeal.get(idx));
});
cardsToDeal.clear();
You're talking about Java 8's Function API (and lambdas).
Essentially lambdas are a shorthand brethren to functions/methods, they have inputs and potentially return values. For the #forEach, it requests that you provide a function which accepts a T (Your list type), and returns nothing. This is known as a Consumer. The method then takes the Consumer you gave it, and calls it for each element on your list.
For equivalency, these are essentially the same thing as far as you're concerned when developing:
void someConsumerMethod(Card c) {
//lambda code block
}
(Card c) -> //lambda code block
this::someConsumerMethod //direct reference to the first method
An example would be:
this.cards.forEach(c -> {
System.out.println(c); //fully expanded
});
this.cards.forEach(c -> System.out.println(c)); //shorthand / one-liner
//or, since println already matches a Consumer<Object>, we can method reference it!
this.cards.forEach(System.out::println);
As for adapting your example, I wouldn't recommend modifying a collection while you iterate it (at least, not without using Iterator#remove). Andy Turner's answer already shows you how to use an application of IntStream to iterate the indexes you want.
What you are looking for is lambda expressions. The forEach method takes a functional interface (an interface with one abstract method), meaning it can be used as follows:
List<String> myList;
myList.forEach((String s) -> System.out.println(s));
Source: http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/Lambda-QuickStart/index.html
You mean you want to use new Java 8 streams with your List.
So the syntax is like:
this.cards.stream().forEach(card -> {// do something here});
You can call stream() to access the method forEach().
Or directly with your List:
this.cards.forEach(...);
In my example I use the new Java 8 arrow functions that is a convenient way to avoids the boiler plate of the anonymous class (much an evolution).
You can pass a method to the forEach():
this.cards.stream().forEach(doSomethingWithMyCard);
You may keep track of the current player index, and iterate over the cards pack, to distribute it entirely :
int playerIndex = 0;
for(Card card : cards){
DealOneCardToPlayer(this.table.players.get(playerIndex) , card);
if(playerIndex == this.table.GetPlayerCount()-1)
playerIndex = 0;
else
playerIndex = playerIndex + 1;
}
If you only want to distribute one card per player, replace
if(playerIndex == this.table.GetPlayerCount()-1)
playerIndex = 0;
else
playerIndex = playerIndex + 1;
With :
if(playerIndex == this.table.GetPlayerCount()-1)
break;
Your example is not really suitable to be converted to a forEach call because you have all those extra conditions in there and stuff. You are also modifying the list in the for loop. Because of these reasons, you better stick with a for loop.
A forEach call can be used when you want to mutate the objects in a list, or you just want to access each item in the list.
The syntax looks like this:
list.forEach(item -> <insert the stuff you want to do to the item here>);
Here are some examples showing how to use forEach. I also provided the equivalent for loop:
// forEach
list.forEach(item -> item.setSomeProperty(1));
// for loop
for (int i = 0 ; i < list.size() ; i++) {
list.get(i).setSomeProperty(1);
}
// forEach
list.forEach(item -> item.doStuff());
// for loop
for (int i = 0 ; i < list.size() ; i++) {
list.get(i).doStuff()
}
// forEach
list.forEach(item -> System.out.println(item));
// for loop
for (int i = 0 ; i < list.size() ; i++) {
System.out.println(list.get(i));
}
Hopefully you can understand the syntax by looking at the above examples.
Note that the last example can be simplified to:
list.forEach(System.out::println);
We're basically telling it to call System.out::println on each item.
if I have a list of arrays like this (pseudo java code):
Note the list valsSorted will be always sorted with x[0] asc and x[1] desc order.
List valsSorted = {[1 5][1 4][1 3][2 1][3 2][3 1][4 2][4 1][5 1][6 2][6 1]};
How do I filter this list with Java 8 streams and lambdas so that I get:
result = {[1 5][2 1][3 2][4 2][5 1][6 2]}
The first item of the array (x[0]) is ID and the second is a version number. So the rule is give all distinct IDs with the highest version back.
If I would use a for loop the following code would be fine:
ArrayList<int[]> result= new ArrayList();
int keep = -1;
for (int[] x : valsSorted) {
int id = x[0];
int version = x[1];
if(keep == id) continue;
keep = id;
result.add(x);
}
Your use of the word "distinct" suggests using the distinct() stream operation. Unfortunately that operation is hardwired to use the equals() method of the stream elements, which isn't useful for arrays. One approach for dealing with this would be to wrap the arrays in a wrapper object that has the semantics of equality that you're looking for:
class Wrapper {
final int[] array;
Wrapper(int[] array) { this.array = array; }
int[] getArray() { return array; }
#Override
public boolean equals(Object other) {
if (! (other instanceof Wrapper))
return false;
else
return this.array[0] == ((Wrapper)other).array[0];
}
#Override
public int hashCode() { ... }
}
Then wrap up your object before distinct() and unwrap it after:
List<int[]> valsDistinct =
valsSorted.stream()
.map(Wrapper::new)
.distinct()
.map(Wrapper::getArray)
.collect(toList());
This makes one pass over the data but it generates a garbage object per value. This also relies on the stream elements being processed in-order since you want the first one.
Another approach would be to use some kind of stateful collector, but that will end up storing the entire result list before any subsequent processing begins, which you said you wanted to avoid.
It might be worth considering making the data elements be actual classes instead of two-element arrays. This way you can provide a reasonable notion of equality, and you can also make the values comparable so that you can sort them easily.
(Credit: technique stolen from this answer.)
class Test{
List<Point> valsSorted = Arrays.asList(new Point(1,5),
new Point(1,4),
new Point(1,3),
new Point(2,1),
new Point(3,2),
new Point(3,1),
new Point(4,2),
new Point(4,1),
new Point(5,1),
new Point(6,2),
new Point(6,1));
public Test(){
List<Point> c = valsSorted.stream()
.collect(Collectors.groupingBy(Point::getX))
.values()
.stream()
.map(j -> j.get(0))
.collect(Collectors.toList());
for(int i=0; i < c.size(); i++){
System.out.println(c.get(i));
}
}
public static void main(String []args){
Test t = new Test()
}
}
I decided to use the point class and represent the ID field as x and the version number as Y. So from there if you create a stream and group them by ID. You can call the values method which returns a Collection of Lists Collection<List<Point>>. You can then call the stream for this Collection and get the first value from each list which according to your specifications is ordered with descending version number so it should be the the highest version number. From there all you have to do is collect them into a list, array or whatever you see necessary and assign it as needed.
The only problem here is that they are printed out of order. That should be an easy fix though.
In JavaScript, I can write code like this:
var a = new Array();
a[2] = 'a';
a[20] = 'b';
and this would not work on Java, the point is I don't want to specific the exact length for it.
How could I keep this happy style when writing java?
If you don't want to specific length you can use List like this:
List<Character> list = new ArrayList<>();
list.add('a');
list.add('b');
You cannot. Java is to Javascript as ham is to hamster. There is no reason to believe they have the same syntax.
If you want a sparse array, use a Map:
final Map<Integer, Character> a = new LinkedHashMap<>();
a.put(2, 'a');
a.put(20, 'b');
When you want an array of characters you can do it like this:
char[] array = new char[30];
array[2] = 'a';
array[20] = 'b';
Java and JavaScript are two deferent languages. you can't do same thing in both
In Java you can write
char[] arr=new char[2];
arr[0]='a';
arr[1]='b';
If you don't want to specific the length, you can use List in Java
List<Character> list=new ArrayList<>();
list.add('a');
list.add('b');
As others already pointed out: Java and JavaScript are two different things. For containers with variable size there is the Java collections framework.
But wich to choose? That depends on what you need. From your question I can imagine two cases:
a variable sized, indexed container:
basically an array-like list. In Java there's besides other list implementations the ArrayList used as follows:
List<Character> myList = new ArrayList<Character>();
// insert element at the end of the list
myList.add('a');
// insert element at specific position in list
myList.add(1, 'b');
// this will fail, because there's no element at position 2!!!
myList.add(3, 'c')
a container for mappings from integer to character:
In java there's lots of map implementations, I propose the HashMap, used like this:
Map<Integer,Character> myMap = new HashMap<Integer,Character>();
// insert mappings int -> char
myMap.put(0, 'a');
myMap.put(1, 'b');
myMap.put(20, 'c');
Each Container serves a different purpose. I advise reading the Java collections tutorial to be able to choose the best fitting one. Also take a look at tucuxi's answer, as he presented a solution wich simulates the desired beahviour but consider that (as he said himself) this is not the java way of doing things!
You can always write your own. You will not get the syntax, but most of the flavor will still be there.
Note that, efficiency-wise, this is a terrible idea. You can write much better code by learning "the Java way" of doing things. This is true of all languages: programming against the grain of the language is sure to cause you pain.
But here is the code:
class MyArray<T> extends ArrayList<T> {
public MyArray<T>() { super(); }
public void add(int i, T value) {
if (size() < i) {
ensureCapacity(i+1); // grow at most once instead of multiple times
while (size() < i)) {
add(null); // extend with a null object
}
add(value);
} else {
add(i, value);
}
}
}
Now you can compare a garden-variety ArrayList with an instance of MyArray:
ArrayList<Character> a = new ArrayList<>();
MyArray<Character> b = new MyArray<>()
a.add(10, 'X'); // IndexOutOfBoundsException, size is 0
b.add(10, 'X'); // no exception - you get [10 x null, 'X']
b.get(10); // returns 'X'
Bear in mind that JavaScript arrays can be indexed by arbitrary objects and not only integers -- but that the JavaScript VM tries to use numerically-indexed arrays if at all possible. For arbitrary indexing, you would need to use a Java HashMap:
class MyArray2<T> extends HashMap<Object, T> {
public MyArray2<T>() { super(); }
public void add(Object o, T value) { set(o, value); }
}
You would then use as:
MyArray2<Character> c = new MyArray2<>()
c.add("anything", '?');
c.get("anything"); // returns '?'
It depends, if you are going to use an array of a fixed size you can use:
char myarray[]=new char[50];
myarray[2]='a';
myarray[20]='b';
If you are going to change the size of the array dynamically you can use a Collection like an ArrayList (look at the doc) and insert chars in the positions you want
like this
char arr[]=new char[30]; //declares an array which can hold 30 characters
arr[2]='a';
arr[20]='b';
but if you don't want to specify the length,than arraylist is something which will help you to accomplish your task because array's size is always fixed in Java
I've inherited a bunch of code that makes extensive use of parallel arrays to store key/value pairs. It actually made sense to do it this way, but it's sort of awkward to write loops that iterate over these values. I really like the new Java foreach construct, but it does not seem like there is a way to iterate over parallel lists using this.
With a normal for loop, I can do this easily:
for (int i = 0; i < list1.length; ++i) {
doStuff(list1[i]);
doStuff(list2[i]);
}
But in my opinion this is not semantically pure, since we are not checking the bounds of list2 during iteration. Is there some clever syntax similar to the for-each that I can use with parallel lists?
I would use a Map myself. But taking you at your word that a pair of arrays makes sense in your case, how about a utility method that takes your two arrays and returns an Iterable wrapper?
Conceptually:
for (Pair<K,V> p : wrap(list1, list2)) {
doStuff(p.getKey());
doStuff(p.getValue());
}
The Iterable<Pair<K,V>> wrapper would hide the bounds checking.
From the official Oracle page on the enhanced for loop:
Finally, it is not usable for loops
that must iterate over multiple
collections in parallel. These
shortcomings were known by the
designers, who made a conscious
decision to go with a clean, simple
construct that would cover the great
majority of cases.
Basically, you're best off using the normal for loop.
If you're using these pairs of arrays to simulate a Map, you could always write a class that implements the Map interface with the two arrays; this could let you abstract away much of the looping.
Without looking at your code, I cannot tell you whether this option is the best way forward, but it is something you could consider.
This was a fun exercise. I created an object called ParallelList that takes a variable number of typed lists, and can iterate over the values at each index (returned as a list of values):
public class ParallelList<T> implements Iterable<List<T>> {
private final List<List<T>> lists;
public ParallelList(List<T>... lists) {
this.lists = new ArrayList<List<T>>(lists.length);
this.lists.addAll(Arrays.asList(lists));
}
public Iterator<List<T>> iterator() {
return new Iterator<List<T>>() {
private int loc = 0;
public boolean hasNext() {
boolean hasNext = false;
for (List<T> list : lists) {
hasNext |= (loc < list.size());
}
return hasNext;
}
public List<T> next() {
List<T> vals = new ArrayList<T>(lists.size());
for (int i=0; i<lists.size(); i++) {
vals.add(loc < lists.get(i).size() ? lists.get(i).get(loc) : null);
}
loc++;
return vals;
}
public void remove() {
for (List<T> list : lists) {
if (loc < list.size()) {
list.remove(loc);
}
}
}
};
}
}
Example usage:
List<Integer> list1 = Arrays.asList(new Integer[] {1, 2, 3, 4, 5});
List<Integer> list2 = Arrays.asList(new Integer[] {6, 7, 8});
ParallelList<Integer> list = new ParallelList<Integer>(list1, list2);
for (List<Integer> ints : list) {
System.out.println(String.format("%s, %s", ints.get(0), ints.get(1)));
}
Which would print out:
1, 6
2, 7
3, 8
4, null
5, null
This object supports lists of variable lengths, but clearly it could be modified to be more strict.
Unfortunately I couldn't get rid of one compiler warning on the ParallelList constructor: A generic array of List<Integer> is created for varargs parameters, so if anyone knows how to get rid of that, let me know :)
You can use a second constraint in your for loop:
for (int i = 0; i < list1.length && i < list2.length; ++i)
{
doStuff(list1[i]);
doStuff(list2[i]);
}//for
One of my preferred methods for traversing collections is the for-each loop, but as the oracle tutorial mentions, when dealing with parallel collections to use the iterator rather than the for-each.
The following was an answer by Martin v. Löwis in a similar post:
it1 = list1.iterator();
it2 = list2.iterator();
while(it1.hasNext() && it2.hasNext())
{
value1 = it1.next();
value2 = it2.next();
doStuff(value1);
doStuff(value2);
}//while
The advantage to the iterator is that it's generic so if you don't know what the collections are being used, use the iterator, otherwise if you know what your collections are then you know the length/size functions and so the regular for-loop with the additional constraint can be used here. (Note I'm being very plural in this post as an interesting possibility would be where the collections used are different e.g. one could be a List and the other an array for instance)
Hope this helped.
With Java 8, I use these to loop in the sexy way:
//parallel loop
public static <A, B> void loop(Collection<A> a, Collection<B> b, IntPredicate intPredicate, BiConsumer<A, B> biConsumer) {
Iterator<A> ait = a.iterator();
Iterator<B> bit = b.iterator();
if (ait.hasNext() && bit.hasNext()) {
for (int i = 0; intPredicate.test(i); i++) {
if (!ait.hasNext()) {
ait = a.iterator();
}
if (!bit.hasNext()) {
bit = b.iterator();
}
biConsumer.accept(ait.next(), bit.next());
}
}
}
//nest loop
public static <A, B> void loopNest(Collection<A> a, Collection<B> b, BiConsumer<A, B> biConsumer) {
for (A ai : a) {
for (B bi : b) {
biConsumer.accept(ai, bi);
}
}
}
Some example, with these 2 lists:
List<Integer> a = Arrays.asList(1, 2, 3);
List<String> b = Arrays.asList("a", "b", "c", "d");
Loop within min size of a and b:
loop(a, b, i -> i < Math.min(a.size(), b.size()), (x, y) -> {
System.out.println(x + " -> " + y);
});
Output:
1 -> a
2 -> b
3 -> c
Loop within max size of a and b (elements in shorter list will be cycled):
loop(a, b, i -> i < Math.max(a.size(), b.size()), (x, y) -> {
System.out.println(x + " -> " + y);
});
Output:
1 -> a
2 -> b
3 -> c
1 -> d
Loop n times ((elements will be cycled if n is bigger than sizes of lists)):
loop(a, b, i -> i < 5, (x, y) -> {
System.out.println(x + " -> " + y);
});
Output:
1 -> a
2 -> b
3 -> c
1 -> d
2 -> a
Loop forever:
loop(a, b, i -> true, (x, y) -> {
System.out.println(x + " -> " + y);
});
Apply to your situation:
loop(list1, list2, i -> i < Math.min(a.size(), b.size()), (e1, e2) -> {
doStuff(e1);
doStuff(e2);
});
Simple answer: No.
You want sexy iteration and Java byte code? Check out Scala:
Scala for loop over two lists simultaneously
Disclaimer: This is indeed a "use another language" answer. Trust me, I wish Java had sexy parallel iteration, but no one started developing in Java because they want sexy code.
ArrayIterator lets you avoid indexing, but you can’t use a for-each loop without writing a separate class or at least function. As #Alexei Blue remarks, official recommendation (at The Collection Interface) is: “Use Iterator instead of the for-each construct when you need to: … Iterate over multiple collections in parallel.”:
import static com.google.common.base.Preconditions.checkArgument;
import org.apache.commons.collections.iterators.ArrayIterator;
// …
checkArgument(array1.length == array2.length);
Iterator it1 = ArrayIterator(array1);
Iterator it2 = ArrayIterator(array2);
while (it1.hasNext()) {
doStuff(it1.next());
doOtherStuff(it2.next());
}
However:
Indexing is natural for arrays – an array is by definition something you index, and a numerical for loop, as in your original code, is perfectly natural and more direct.
Key-value pairs naturally form a Map, as #Isaac Truett remarks, so cleanest would be to create maps for all your parallel arrays (so this loop would only be in the factory function that creates the maps), though this would be inefficient if you just want to iterate over them. (Use Multimap if you need to support duplicates.)
If you have a lot of these, you could (partially) implement ParallelArrayMap<> (i.e., a map backed by parallel arrays), or maybe ParallelArrayHashMap<> (to add a HashMap if you want efficient lookup by key), and use that, which allows iteration in the original order. This is probably overkill though, but allows a sexy answer.
That is:
Map<T, U> map = new ParallelArrayMap<>(array1, array2);
for (Map.Entry<T, U> entry : map.entrySet()) {
doStuff(entry.getKey());
doOtherStuff(entry.getValue());
}
Philosophically, Java style is to have explicit, named types, implemented by classes. So when you say “[I have] parallel arrays [that] store key/value pairs.”, Java replies “Write a ParallelArrayMap class that implements Map (key/value pairs) and that has a constructor that takes parallel arrays, and then you can use entrySet to return a Set that you can iterate over, since Set implements Collection.” – make the structure explicit in a type, implemented by a class.
For iterating over two parallel collections or arrays, you want to iterate over a Iterable<Pair<T, U>>, which less explicit languages allow you to create with zip (which #Isaac Truett calls wrap). This is not idiomatic Java, however – what are the elements of the pair? See Java: How to write a zip function? What should be the return type? for an extensive discussion of how to write this in Java and why it’s discouraged.
This is exactly the stylistic tradeoff Java makes: you know exactly what type everything is, and you have to specify and implement it.
//Do you think I'm sexy?
if(list1.length == list2.length){
for (int i = 0; i < list1.length; ++i) {
doStuff(list1[i]);
doStuff(list2[i]);
}
}