简体   繁体   中英

Removing common elements from two lists of custom objects

In the below code I have two Lists of image objects (fromTagList and fromImageList). The image class has an attribute image URL. There are common objects in the both lists.

My goal is to detect these common elements according to their URL property and remove them from both lists, so that both lists will contain distinct elements together and then I will merge the two lists with one list so that this merged list will contain distinct objects. The problem is that the below method I used did not remove all common elements because I think like this it will skip some indexes.

for (int i = 0; i < fromTagList.size(); i++) {
    for (int k = 0; k < fromImageList.size(); k++) {
        if (fromTagList.get(i).getImageURL().equals(fromImageList.get(k).getImageURL())) {
            fromTagList.remove(i);
            fromImageList.remove(k);
        }
    }
}

.remove(index) takes away the element, which makes the list shorter, but your index doesn't consider that, and keeps adding 1 but that actually steps over 2 elements (the +1 and the removed one).

This works for inline removing of the repeated elements, but it fails when one list contains repeated elements. It works for the case where there are no repeated elements inside a list, because I go through the elements backwards. Do note the labelled continue.

//the new ArrayList is needed so remove is supported
    List<String> fromTagList = new ArrayList(Arrays.asList(new String[] {"a", "b", "c", "1", "2", "3"}));
    List<String> fromImageList = new ArrayList(Arrays.asList(new String[] {"b", "b", "c", "d", "2", "3", "4"}));

    outer: for (int i = fromTagList.size()- 1; i >= 0; i--) {
        for (int k = fromImageList.size() - 1; k >= 0; k--) {
        System.out.println("i: " + i + " k: " + k);
        if (fromTagList.get(i).equals(fromImageList.get(k))) {
            fromTagList.remove(i);
            fromImageList.remove(k);
            continue outer;
        }
        }
    }

    System.out.println("fromTag  : " + fromTagList);
    System.out.println("fromImage: " + fromImageList);

I don't think you can remove as you go if you want to support lists with repeated elements. I suggest adding to a new list of elements to remove.

I would create a dictionary. Iterate through each list (separately). For each object, push it onto the dictionary with the key being its URL. This way, any object with the same URL will appear as one key-value pair in the dictionary. After adding everything to the dictionary, convert the dictionary to a list.

Yeah, You do have a problem of Index, the issue is when you delete something from the list, say at position i=10, the element of position 11 will be in the 10th and i will be in 11 so you will miss this element, the second issue is when you remove from the second list of k indexer, you should break, to not process all the rest elements (unless the element found is not duplicated), so here is my answer that work for me after trying your code:

for (int i = 0; i < fromTagList.size(); i++) {
            for (int k = 0; k < fromImageList.size(); k++) {
                if (fromTagList.get(i).getImageURL().equals(fromImageList.get(k).getImageURL())) {
                    fromTagList.remove(i);
                    fromImageList.remove(k);
                    i--;
                    //break; this is optional
                }
            }
        }

Whenever you need to maintain uniq elements consider using Set<>. The set interface in java is specifically meant to handle uniq elements.You can follow the below approach to convert the lists to a set:

Override the equals and hashcode method for the image object(use only the url attribute as a condition for equality and hascode). Now add both the lists to a set. Convert the set back to a list and voila!! Example:

 class ImageObj {

    String url;
    //rest of the stuff

    @Override
    public boolean equals(Object o){
    ImageObj that = (ImageObj)o;
    return that.url.equals(this.url);
    }
    @Override
    public int hascode(){
    return Objects.hascode(this.url);
    }
    }
    }

Then--

Set<ImageObj> set= new HashSet<ImageObj>(fromTagList);
set.addAll(fromImageList);

List<ImageObj> list = new ArrayList<ImageObj>(set);

This is you final list which contains all unique objects.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM