2 collections are given with the same number of elements, say List<String>
. What are elegant ways in JAVA
to apply a functor on each 2 elements of collections with corresponding indexes?
Say, one example could be:
List<String> = { "APPLE", "PEAR" };
List<String> = { "BANANA", "ORANGE" };
A predicate that joins string together will result in the following List<String>
:
List<String> = { "APPLEBANANA", "PEARORANGE" };
Akin to the functors found in Apache Commons Collections, I have created binary equivalents in the past.
For your situation, a binary transformer type object, which takes to two input objects and returns a single object, could be used. Here is some sample code that's conveys my approach:
// tranformer
interface BinaryTransformer<X, Y, Z> {
Z transform(X a, Y b);
}
// implementation for your problem
class ConcatTransformer implements BinaryTransformer<String, String, String> {
public String transform(String a, String b) {
return a + b;
}
}
// general use transformer
class BinaryListUtils {
public static <X, Y, Z> List<Z> collect(List<X> aList, List<Y> bList, BinaryTransformer<X, Y, Z> t) {
List<Z> ret = new ArrayList<Z>(aList.size());
Iterator<X> aIter = aList.iterator();
Iterator<Y> bIter = bList.iterator();
while(aIter.hasNext()) {
ret.add(t.transform(aIter.next(), bIter.next()));
}
}
}
HTH
A quick driver of this showed it to work. Not responsible for all test cases. :-)
List<String> combineListsHorizontally(List<String> a, List<String> b) {
assert a.size() == b.size(); // just avoids some checks
List<String> result = new ArrayList<String>(a.size());
Iterator<String> itera = a.iterator();
Iterator<String> iterb = b.iterator();
for(int i = 0; i < a.size(); i++) {
String combined = itera.next() + iterb.next();
result.add(combined);
}
return result;
}
If you need something generic, you would need to know they ahve a way that they can be joined
List<E> combineListsHorizontally(List<E> a, List<E> b) {
assert a.size() == b.size(); // just avoids some checks
List<E> result = new ArrayList<E>(a.size());
Iterator<E> itera = a.iterator();
Iterator<E> iterb = b.iterator();
for(int i = 0; i < a.size(); i++) {
E combined = new MagicCombiner<E>(a,b).get(); // define this line yourself
result.add(combined);
}
return result;
}
///////////////// EDIT - here's a working example based off @Brents (superior) example. Props to him for illustrating this pattern better than I did.
import java.util.*;
/**
* Compile: "javac BinaryListUtils"
* Usage: "java BinaryListUtils"
C:\Documents and Settings\user\My Documents>javac BinaryListUtils.java
C:\Documents and Settings\user\My Documents>java BinaryListUtils
APPLEBANANA
PEARORANGE
C:\Documents and Settings\user\My Documents>
*/
// general use transformer
class BinaryListUtils {
// tranformer
static interface BinaryTransformer<X, Y, Z> {
Z transform(X a, Y b);
}
// implementation for your problem
static class ConcatTransformer implements BinaryTransformer<String, String, String> {
public String transform(String a, String b) {
return a + b;
}
}
public static <X, Y, Z> List<Z> collect(List<X> aList, List<Y> bList, BinaryTransformer<X, Y, Z> t) {
List<Z> ret = new ArrayList<Z>(aList.size());
Iterator<X> aIter = aList.iterator();
Iterator<Y> bIter = bList.iterator();
while(aIter.hasNext()) {
ret.add(t.transform(aIter.next(), bIter.next()));
}
return ret;
}
public static void main(String[] args) {
List<String> aList = new ArrayList<String>();
List<String> bList = new ArrayList<String>();
aList.add("APPLE");
aList.add("PEAR");
bList.add("BANANA");
bList.add("ORANGE");
ConcatTransformer ct = new ConcatTransformer();
List<String> cList = BinaryListUtils.collect(aList,bList,ct);
for(String s : cList) System.out.println(s);
}
}
What you're asking for isn't a predicate. It's doing a transformation on the lists zipped together. The generic way to do this is to write an iterable zipper that will zip the two lists into an iterable of a Pair, and then apply the transformation to the pairs.
I initially thought you were asking for the intersection of two collections, which is supplied in Guava collections as Sets.intersection(Set, Set).
I think your best bet here will be to do it iteratively. I can't think of any core Java API that can do it.
public List<String> predicate(List<String> list1, List<String> list2) {
List<String> list = new ArrayList<String>();
for(int i = 0; i < list1.size(); i++) {
list.add(new StringBuilder(list1.get(i)).append(list2.get(i)).toString());
}
return list;
}
Haven't compiled / run it. Good luck.