开发者

Java Arraylist - Copy one to another without duplicates

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.


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.


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());


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


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.


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.


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());
    }
}


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;
            }
        }
    });


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-- );
    }
}


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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜