3

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" };

Leonid
  • 22,360
  • 25
  • 67
  • 91
  • This question is related, but considers a more generic case http://stackoverflow.com/questions/3137944/best-way-to-iterate-over-two-lists-simultaneously – Mark Butler Feb 08 '13 at 05:51

4 Answers4

3

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

Brent Worden
  • 10,624
  • 7
  • 52
  • 57
2

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);


    }
}
corsiKa
  • 81,495
  • 25
  • 153
  • 204
  • can we have a working example,Im unable to follow the example.hope you could simulate with a Main method as well. – Deepak Mar 12 '11 at 14:34
  • Lol really? It's a complete function... Anyway, because @Brent has a superior answer to mine, I'll make one based off his. – corsiKa Mar 12 '11 at 15:29
1

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).

Kevin Peterson
  • 7,189
  • 5
  • 36
  • 43
0

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.

adarshr
  • 61,315
  • 23
  • 138
  • 167
  • That is applicable only for a given predicate, needs to be extended with a class containing a predicate function. – Leonid Mar 11 '11 at 20:50
  • Doesnt StringBuilder costs much more than just to do list1.get(i) + list2.get(i)? – cafebabe Mar 11 '11 at 20:53
  • Sorry, I am not sure I understand predicates here. If you give more examples, I may be able to rig up a method for you. – adarshr Mar 11 '11 at 20:54
  • @oeogijjowefi - Yes, I thought of that too. But I guess it doesn't matter much. Both are nearly same here. – adarshr Mar 11 '11 at 20:55