Translate

Map function in Java

I read on some email signature something along the lines of:
“If I had a dollar for every for(int i=0; i < size; i++) { ... } I've written I'd be rich"

After coding on Android and learning about some of the tips for performance, like
"With an ArrayList, a hand-written counted loop is about 3x faster"

If you do use ArrayLists a lot you then have that tip in the back of your head and you end up with a lot of code like the following:

List<T> myList = ... ;
int size = myList.size();
for (int i=0; i < size; i++) {
  T elem = myList.get(i);
  //do something with elem
}

Eventually there was a moment when I said, I need a freaking map function, I’m sick of this little pattern, surprisingly I couldn’t find a map() function anywhere on the java collection framework. So I went and did this.

Warning: These mapping utilities are meant only for Lists with RandomAccess capabilities (.get(i) happens in constant time). Do not use with LinkedList or other lists that don’t implement RandomAccess, otherwise you’ll end up with up to O(n^2) times. Thanks to Roger Kapsi for noticing this issue. [you can now tell how much we like to use ArrayList]

//what I think would be the equivalent of a lambda or closure in Python...
public interface MapFunction<T> {
   public void map(T t);
}

And then on one of my utils classes I added a static method map that looks like this:

public static <T> void map(List<T> list, MapFunction<T> mapFunction) {
int size=list.size();
   for (int i=0; i < size; i++) {
      mapFunction.map(list.get(i));
   }
}

So now, everytime I need to iterate over a whole list and do something to each element it’s a lot cleaner

//let's serialize all the messages...
List<Message> messages = ...;
Utils.map(messages, new MapFunction<Message> {
   public void map(Message message) {
      Engine.INSTANCE.SERIALIZER.save(message);
   }
});

done deal.

Update

Here’s another Map utility that let’s your map() function know about the index of your current element. You may have to treat certain elements differently based on their position in the list.
This time your function takes a “IndexMapFunction” implementation.

public static <T> void map(List<T> list, IndexedMapFunction<T> mapFunction) {
		int size = list.size();
		for (int i = 0; i < size; i++) {
			mapFunction.map(i, list.get(i));
		}
}

The interface for IndexedMapFunction looks like this

public interface IndexedMapFunction<T> {
	public void map(int i, T obj);
}

In your implementation of “map(int i, T obj)”, “i” represents the position of the element being treated. You could do different things depending on what position of the List you are. For example, you could know if you’re at the beggining or end of the list, or maybe you could other data structure telling you things about some positions in the list in question.

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)

3 Responses to “Map function in Java”

  1. Roger Says:

    I would change the map() function to the following because the statement is only true for some Lists, in particular ArrayList but not for all Lists. Your for loops will be crippled to an O(n**2) operation if you pass a LinkedList to it for example and that’s something you want to avoid at all cost.

    public static void map(Iterable elements, MapFunction mapFunction) {
    if (elements instanceof List && elements instanceof RandomAccess) {
    List list = (List)elements;
    int size = list.size();
    for (int i = 0; i < size; i++) {
    mapFunction.map(list.get(i));
    }
    } else {
    for (T element : elements) {
    mapFunction.map(element);
    }
    }
    }

  2. Roger Says:

    Also, the MapFunction has no clue about the context of the elements. You can therefore let the for loop run backwards and save the size variable.

    for (int i = list.size()-1; i >= 0; –i) {
    mapFunction.map(list.get(i));
    }

  3. gubatron Says:

    You are right sir. We have been using that map function only with ArrayList which implements get() in constant time, otherwise you end up with very sucky N^2 performance.

Leave a Reply