Firstly, I apologize for posting similar question to "4462626". I want to compare to two objects (which are parent-child relationship). How do you think following code. I think it is not efficient because too many for-loops exist. Can you advice me? (notice: I am not allowed to modify Item.class and ItemEx.class must extend Item.class)
EXPECTED RESULT
------------------------
add:4
delete:2
------------------------
package com.javastudy;
import java.util.ArrayList;
import java.util.List;
public class CollectionCompareToObjectsForLoop {
public static void main(String[] args) {
List<Item> beforeList = new ArrayList<Item>();
List<ItemEx> afterList = new ArrayList<ItemEx>();
beforeList.add(new Item(1L));
beforeList.add(new Item(2L)); // delete
beforeList.add(new Item(3L));
afterList.add(new ItemEx(1L));
afterList.add(new ItemEx(3L));
afterList.add(new ItemEx(4L)); // added
// Check Add
List<Item> addList = new ArrayList<Item>();
for(Item afterItem : afterList){
if(checkAdd(afterItem, beforeList)){
addList.add(afterItem);
}
}
// Check Delete
List<Item> deleteList = new ArrayList<Item>();
for(Item beforeItem : beforeList){
if(checkDelete(beforeItem, afterList)){
deleteList.add(beforeItem);
}
}
// Print Result
for(Item item : addList){
System.out.println("add:" + item.getId());
}
for(Item item : deleteList){
System.out.println("delete:" + item.getId());
}
}
private static boolean checkAdd(Item afterItem, List<Item> beforeList) {
for(Item beforeItem : beforeList){
if (afterItem.getId().equals(beforeItem.getId())){
return false;
}
}
return true;
}
private static boolean checkDelete(Item beforeItem, List<ItemEx> afterList) {
for(Item afterItem : afterList){
if (beforeItem.getId().equals(afterItem.getId())){
return false;
}
}
return true;
}
}
package com.javastudy;
public class Item {
private Long id;
public Item(Long id) {
this.id = id;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
package com.javastudy;
public class ItemEx extends Item {
private String name;
public ItemEx(Long id) {
super(id);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
I assume that the Id
s you gave to the items are really IDs, so that items having the same ID are considered equal and that there is only one item per ID. Then you can use the following code:
package so4483619;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class AddDel {
private static <K, V> HashMap<K, V> newLinkedHashMap() {
return new LinkedHashMap<K, V>();
}
private static <K, V> HashMap<K, V> newLinkedHashMap(Map<? extends K, ? extends V> other) {
return new LinkedHashMap<K, V>(other);
}
private static void computeDeleteAndAdd(List<? extends Item> before, List<? extends Item> after) {
Map<Long, Item> beforeById = newLinkedHashMap();
for (Item item : before) {
beforeById.put(item.getId(), item);
}
Map<Long, Item> afterById = newLinkedHashMap();
for (Item item : after) {
afterById.put(item.getId(), item);
}
Map<Long, Item> onlyBefore = newLinkedHashMap(beforeById);
onlyBefore.keySet().removeAll(afterById.keySet());
Map<Long, Item> onlyAfter = newLinkedHashMap(afterById);
onlyAfter.keySet().removeAll(beforeById.keySet());
for (Map.Entry<Long, Item> entry : onlyBefore.entrySet()) {
System.out.println("delete:" + entry.getKey());
}
for (Map.Entry<Long, Item> entry : onlyAfter.entrySet()) {
System.out.println("add:" + entry.getKey());
}
}
public static void main(String[] args) {
List<Item> beforeList = new ArrayList<Item>();
List<ItemEx> afterList = new ArrayList<ItemEx>();
beforeList.add(new Item(1L));
beforeList.add(new Item(2L)); // delete
beforeList.add(new Item(3L));
afterList.add(new ItemEx(1L));
afterList.add(new ItemEx(3L));
afterList.add(new ItemEx(4L));
computeDeleteAndAdd(beforeList, afterList);
}
}
Some remarks:
LinkedHashMap
behaves like a map but remembers the order in which the elements have been inserted. This is to make the output predictable and to have the same order as in the beforeList
and afterList
.Item
and ItemEx
don't have the methods equals(Object)
and hashCode()
, so they cannot be used directly as keys in a HashMap
. This is my assumption that you consider two Item
s with the same ID to be equal.newLinkedHashMap
just save some keystrokes in the method computeDeleteAndAdd
. Without these methods you would have to say new LinkedHashMap<Long, Item>(...)
instead of a simple newLinkedHashMap(...)
.