5

I'm looking for an efficient design pattern to map one list of objects to another list of objects with zero-or-one-to-one relationships between them. I realize this sort of thing is typically done in a relational database, but in this particular case it really needs to be done in the Java application...

Let's say the first list contains Foo objects (i.e. List<Foo>):

public class Foo {
    public Integer id;
    public String barName;
}

And the second list contains Bar objects (i.e. List<Bar>):

public class Bar {
    public Integer fooId;
    public String name;
}

How can I most efficiently map all name properties from Bar to the Foo object where Bar.fooId equals Foo.id?

The best I can think of is this:

void mapFooBar(List<Foo> fooList, List<Bar> barList) {
    for (Bar bar : barList) {
        for (Foo foo : fooList) {
            if (bar.fooId.equals(foo.id)) foo.barName = bar.name;
        }
    }
}

EDIT: Based on several answers, I have improved my code as follows:

void mapFooBar(List<Foo> fooList, List<Bar> barList) {
    Map<Integer, String> barMap = new HashMap<Integer, String>();
    for (Bar bar : barList)
        barMap.put(bar.fooId, bar.name);

    for (Foo foo : fooList)
        if (barMap.containsKey(foo.id)) foo.barName = barMap.get(foo.id);
}

Is there a better way?

2

6 Answers 6

2

I think what you are looking for is something like Apache BeanUtils or Springs implementation. Just make sure the properties are named the same between the 2 objects you want to copy the data between. So taking your code:

void mapFooBar(List<Foo> fooList, List<Bar> barList) {
  for (Bar bar : barList) {
    for (Foo foo : fooList) {
        if (bar.fooId.equals(foo.id)) {
            BeanUtils.copyProperties(foo, bar);
        }
    }
  }
}

Now that the copy is done lets look at your loop. Your best bet would be to keep the Objects in Maps using fooId as the key (assuming no objects duplicated).

void mapFooBar(Map<Integer, Foo> fooMap, Map<Integer, Bar> barMap) {
  for (Integer key : fooMap.keySet()) {
    if (barMap.containsKey(key) {
      Bar bar = barMap.get(key);
      Foo foo = fooMap.get(key);
      BeanUtils.copyProperties(foo, bar);
    }
  }
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for your response! I agree with your suggestion for improving the loop using a map, as others have suggested, but I don't see the benefit of using BeanUtils.copyProperties(foo, bar) since I only need to map a single property.
Gotcha, I thought you only put in a single property as an example. Leave out the BeanProperties then.
1

This has complexity of N * M that means if you have 5 foo and 8 bar it would have to execute loop for 40 times

class Container{

  List<Foo> foos;
  List<Bar> bars;

}

if you use Map<Integer, Container> it would be N + M (5 + 8 = 13 times)

iterate through both list once and map it with id


Also See

1 Comment

Thank you for your response. I don't quite follow...could you illustrate how this would be used to map values from bars to foos?
1

Take a look at Orika, an efficient Java Object to Object Mapping

https://github.com/orika-mapper/orika

Comments

1

In Java 1.8 you can write it like this:

void mapFooBar(List<Foo> fooList, List<Bar> barList) {

    Map<Integer, String> barMap = new HashMap<Integer, String>();

    barList.stream()
        .forEach(bar -> barMap.put(bar.fooId, bar.name));

    fooList.stream()

        // replaces if statement
        .filter(foo -> barMap.containsKey(foo.id))

        // update the bar name
        .forEach(foo -> {
            foo.barName = barMap.get(foo.id);
        });
}

Comments

1

Hmm. Assuming the "primary keys" were unique I might convert the list of Bar to a map with fooId as the key and either whole object or the name as the value. Then I would iterate through the list of Foo and see whether the id property existed in the map. If it did I would map the bar.name to foo.barName;

1 Comment

Thanks for the response! Based on your answer and @Jigar's answer, I see that looping through List<Bar> once to create a map, then looping through List<Foo> once to check against the map keys, is more efficient than doing the nested loop. And yes, my ids are unique.
0

You could use a HashMap to store all Foo objects, with their id as key.

Then loop through Bar list and access directly HashMap position you want

1 Comment

What type of HashMap because I have attributes of type String, Integer and sql.Date

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.