views:

403

answers:

9

How do I, without using any loop, modify the values in a collection to get a new collection with the modified values?

For example, I'm having a Collection<String> and want to surround all Strings by parentheses.

With a loop I would do this:

Iterable<String> collection = getCollection();
ArrayList<String> newCollection = new ArrayList<String>();    
for(String str : collection) 
    newCollection.add("(" + str + ")");

There has to be a more elegant solution.

EDIT: Use of third party utilities is allowed :)

+7  A: 

no, there isn't. Using only JDK classes you cannot do it better. Check my second answer

EDIT

try google collection library Lists.trasform:

List<String> out = Lists.transform(in, new Function<String, String>() {

    public String apply(String s) {
        return String.format("(%s)", s);
    }
});
dfa
Use of third party is allowed :)
Markus Lux
+1 for the readability of this part: String.format("(%s)", s);
Peter Perháč
You're just passing off the loop, though.
quillbreaker
The idea of "modifying without loop" is almost similar to "run application without executable", someone has to hide the loop somewhere.
Esko
of course :-)
dfa
+2  A: 

You can use CollectionUtils.transform from Apache commons collections.

MarrLiss
+2  A: 

Use Apache Commons CollectionUtils:

List l = someList;
CollectionUtils.transform(l, new Transformer() {
    public Object transform(Object o)
    {
        String s = (String) o;
        return "(" + s + ")";
    }
});
Yuval A
+2  A: 

It's sounds to me like you're trying to use functional idioms with Java. While this can be achieved using third party libs and functor (as others have suggested), I would recommend programming Java using Java idioms or use a functional language. If you want a JVM-compatible functional language, look at Scala.

Draemon
A: 

That's actually a Java shortage which has been discussed a lot. In many languages you can do that in just one line of code using closures (or code blocks). For instance, in Groovy you can write it as follows:

newCollection = collection.collect { "($it)" }

I wish, we can do this in java 7.

clojures was rejected for Java 7
dfa
Oh, what a bad news! I haven't been reading the news for some months and I didn't know what was going on. I just searched for that and unfortunately, it seems you're true. http://www.infoq.com/news/2009/01/java7-updated
+1  A: 

You want a Map function. Those are available (among other things) in functional java. Example code:

import fj.F;
import fj.data.List;
import static fj.data.List.*;
import static fj.pre.Show.listShow;
import static fj.pre.Show.stringShow;

import static java.lang.String.format;

public class Test {

    public static void main(String[] args) {

        List<String> a = list("a", "b", "c");
        List<String> b = a.map(new F<String, String>() {

            public String f(String s) {
                return format("(%s)", s);
            }

        });

        listShow(stringShow).println(a);
        listShow(stringShow).println(b);

    }

}
yawn
A: 

my previous answer was functional oriented, now, meanwhile I'm cooking "spaghetti al pomodoro", I'm thinking about a more object oriented approach.

What do you think about an anonymous class implementation that overrides it's iterator with one that enclose it's element around ()?

public static <T> Collection<String> wrap(final Collection<T> collection) {
    final Iterator<T> iterator = collection.iterator();
    return new AbstractCollection<String>() {

        @Override
        public int size() {
            return collection.size();
        }

        @Override
        public Iterator<String> iterator() {
            return new Iterator<String>() {

                public boolean hasNext() {
                    return iterator.hasNext();
                }

                public String next() {
                    return String.format("(%s)", iterator.next());
                }

                public void remove() {
                    iterator.remove();
                }
            };
        }
    };
}

demo

List<String> in = Arrays.asList("aaa","bbb");
List<String> out = new ArrayList<String>(wrap(in));
System.out.println(out);

outputs:

[(aaa), (bbb)]

BTW this only uses JDK classes and uses no loops!

dfa
+1  A: 

How do I, without using any loop, modify the values in a collection to get a new collection with the modified values?

Why would you want to? As Java does not have closures, this is often more complicated, non-standard and more difficult to read.

You will note that your example is shorter and simpler than the alternative solutions and it uses standard java.

BTW: loops are still used, just not directly by you so the distinction is an illusion.

Peter Lawrey
+1  A: 

Check out the lambdaj library

http://code.google.com/p/lambdaj/

and you will discover a huge set of handful methods to manipulate collection in a DSL style without writing a single explicit loop

Mario Fusco
+1 a very good, inspiring library
dfa