4

I have an ArrayList:

Arraylist<Person> list1 = new ArrayList<Person>();
list1.add(new Person("John", 0));
list1.add(new Person("Kane", 0));
list1.add(new Person("Jen", 0));

And another ArrayList:

Arraylist<Person> list2 = new ArrayList<Person>();
list2.add(new Person("John", 2));
list2.add(new Person("Kane", 4));

I want the resulting ArrayList to contain:

("John", 2) ("Kane", 4) ("Jen", 0)

I want to merge these two lists and remove the ones that have the value 0. If I did list2.addAll(list1), then list2 has two entries for "John" with the values of 2 and 0. I want to remove the entry with the value of 0 from this list.

3
  • 1
    Can't you use a Set to remove the dups? Commented Aug 24, 2010 at 18:32
  • 1
    As long as your Person object has a good equals and hashCode override method using a Set to remove the dups is perfectly ok. You'll find some people that argue about performance, but I mean, you'll have to take a performance hit somewhere since you have to loop over all the records anyway. You may as well let Java do it for you. Commented Aug 24, 2010 at 18:36
  • @Harish - what should happen if both values are not zero? Commented Aug 25, 2010 at 7:16

9 Answers 9

8

Um it sounds like, in your program logic, creating a

new Person("John", 2)

isn't what you want - is there really a 'new person' called John? or is it the same old John who has a new score? Perhaps you need a function to update the scores in the individual people like

Person.setValue(int)

Sorry if this doesn't actually answer your question, but it's very important to check you have the right kind of data structures.

Sign up to request clarification or add additional context in comments.

Comments

2

Seems like you want the maximum value for each user:

List<Person> all = new ArrayList<Person>();
all.addAll(list1);
all.addAll(list2);

Map<String, Person> map = new HashMap<String, Person>();
for (Person p : all) {
    if (!map.containsKey(p.name) || map.get(p.name).num < p.num) {
        map.put(p.name, p);
    }
}
List<Person> merged = new ArrayList<Person>(map.values());

2 Comments

Not sure if this is the best solution out there, but it works for me. Thanks richard
That depends on whether my assumption about what you're trying to do is correct. Do you want the maximum value?
2

Is order important? If not, a Set makes more sense than a List. Set has historically been underused with programmers thinking in terms of arrays.

If order isn't important, a rather hacky approach would be to use a TreeSet with custom comparator. Alternatively, use a Map<String,Person> (possibly a LinkedHashMap).

1 Comment

@Alex - and how does that check which entry has a non-zero value?
2

It looks to me like what you really want is a Map. Create one of those, and for each Person in either list, put the value 0 into the map with the person's name as the key. Now, for each Person in each list, get the value for the person's name from the map, add the person's value to it, and store the result back into the map. Now, if you really need it in the ArrayList, it's a simple matter to extract key-value pairs from the map into a new list.

Comments

1

Create a Comparator that compare them just by name (if you don't already have an equals() that does it).

Order the Lists by decrescent order on the person's value (considering value is positive. Is it?)

Then, create a set based on this Comparator. Now you can call addAll.

Comments

1

From your example, it appears that a Map from name to whatever-the-number-means is a more appropriate data structure. With such maps, you'd simply do:

map1.putAll(map2);

If you don't want the second map to win, but the entry with the higher value, you'll have to do something like:

for (Map.Entry<String, Integer> e : map2.entrySet()) {
    Integer v = map1.get(e.getKey());
    if (v == null || v < e.getValue()) {
        map1.put(e.getKey(), e.getValue());
    }
}

Comments

1

What about this?

In Person class:

@Override
public boolean equals(Object obj) {
    Person o = (Person) obj;
    if (o.getNombre().equals(this.nombre)) {            
        return true;    
    }
    return false;
}

then:

    list2.addAll(list1);
    final ArrayList<Person> list3 = list2;
    CollectionUtils.filter(list2, new Predicate() {         

        public boolean evaluate(Object arg0) {
            if (((Person) arg0).getId() == 0 && CollectionUtils.cardinality(arg0, list3) > 1) {
                return false;
            } else {
                return true;
            }
        }
    });

1 Comment

Is CollectionUtils standard java? Where it comes from, apache?
0

What about...

ArrayList<Person> list3 = new ArrayList<Person>();
list3.addAll( list1 );
list3.addAll( list2 );

System.out.println( "BEFORE" );
for ( Person person : list3 )
    System.out.println( person.getName() + " = " + person.getIntParam() );

filterPeople( list3 );

System.out.println( "AFTER" );
for ( Person person : list3 )
    System.out.println( person.getName() + " = " + person.getIntParam() );

Filter method:

public static void filterPeople( List<Person> people ) {
    for ( int i = 0 ; i < people.size(); i++ ) {
        Person person = people.get( i );
        if ( person.getIntParam() == 0 )
            people.remove( i-- );
    }
}

1 Comment

I think he wants only the duplicates with value 0 removed, not all entries with 0.
0

Using a Map sounds like your best bet, a Set would work too. bBe sure to have Person provide proper equals and hashCode implementations.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.