tags:

views:

169

answers:

9

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.

+1  A: 

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.

Rodrigo Gama
+1  A: 

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());
    }
}
meriton
+2  A: 

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).

Tom Hawtin - tackline
set.addall(list); // done!
Alex Feinman
@Alex - and how does that check which entry has a non-zero value?
Carlos Heuberger
+2  A: 

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.

Carl Manaster
+8  A: 

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.

Sanjay Manohar
+1 for suggesting a step back
Hemal Pandya
+2  A: 

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());
Richard Fearn
Not sure if this is the best solution out there, but it works for me. Thanks richard
Harish
That depends on whether my assumption about what you're trying to do is correct. Do you want the maximum value?
Richard Fearn
A: 

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-- );
    }
}
Andy
I think he wants only the *duplicates* with value `0` removed, not all entries with `0`.
Carlos Heuberger
A: 

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

Echidna
+1  A: 

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;
            }
        }
    });
hgmiguel
Is `CollectionUtils` standard java? Where it comes from, apache?
Carlos Heuberger
No, is not standard, comes from apache commons...
hgmiguel