Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python-like list comprehension in Java

Since Java doesn't allow passing methods as parameters, what trick do you use to implement Python like list comprehension in Java ?

I have a list (ArrayList) of Strings. I need to transform each element by using a function so that I get another list. I have several functions which take a String as input and return another String as output. How do I make a generic method which can be given the list and the function as parameters so that I can get a list back with each element processed. It is not possible in the literal sense, but what trick should I use ?

The other option is to write a new function for each smaller String-processing function which simply loops over the entire list, which is kinda not so cool.

like image 293
euphoria83 Avatar asked May 22 '09 17:05

euphoria83


People also ask

Does Java have list comprehensions?

We got able to implement the functions map and filter using list comprehensions written in set-builder notation, Haskell and Java code, the latest one with an implementation of this article.

Which is faster lambda or list comprehension?

Actually, list comprehension is much clearer and faster than filter+lambda, but you can use whichever you find easier. The first thing is the function call overhead: as soon as you use a Python function (whether created by def or lambda) it is likely that the filter will be slower than the list comprehension.

What is faster than list comprehension?

For loops are faster than list comprehensions to run functions.

Are list comprehensions faster than map?

Map function is faster than list comprehension when the formula is already defined as a function earlier. So, that map function is used without lambda expression.


2 Answers

In Java 8 you can use method references:

List<String> list = ...; list.replaceAll(String::toUpperCase); 

Or, if you want to create a new list instance:

List<String> upper = list.stream().map(String::toUpperCase).collect(Collectors.toList()); 
like image 171
yurez Avatar answered Sep 23 '22 05:09

yurez


Basically, you create a Function interface:

public interface Func<In, Out> {     public Out apply(In in); } 

and then pass in an anonymous subclass to your method.

Your method could either apply the function to each element in-place:

public static <T> void applyToListInPlace(List<T> list, Func<T, T> f) {     ListIterator<T> itr = list.listIterator();     while (itr.hasNext()) {         T output = f.apply(itr.next());         itr.set(output);     } } // ... List<String> myList = ...; applyToListInPlace(myList, new Func<String, String>() {     public String apply(String in) {         return in.toLowerCase();     } }); 

or create a new List (basically creating a mapping from the input list to the output list):

public static <In, Out> List<Out> map(List<In> in, Func<In, Out> f) {     List<Out> out = new ArrayList<Out>(in.size());     for (In inObj : in) {         out.add(f.apply(inObj));     }     return out; } // ... List<String> myList = ...; List<String> lowerCased = map(myList, new Func<String, String>() {     public String apply(String in) {         return in.toLowerCase();     } }); 

Which one is preferable depends on your use case. If your list is extremely large, the in-place solution may be the only viable one; if you wish to apply many different functions to the same original list to make many derivative lists, you will want the map version.

like image 26
Michael Myers Avatar answered Sep 23 '22 05:09

Michael Myers