简体   繁体   中英

Removing common elements between two different Arraylist

I have read several posts for this but not getting the exact thing I am looking for. I know how to develop a complex logic for this, this is for Android and we can't expect too much processing on the device due to the limited resources available.

I have an ArrayList of an bean class objects consisting five fields as

Java Bean -- MyShares

  1. fileName
  2. filePath
  3. fileSize
  4. isShared
  5. Creator

I have another ArrayList of String which contains only filepaths. Now what I want is to remove all the common elements between the two arraylist means the file paths in seconds arraylist and file path in first arraylist objects are similar then I have to remove from both of the arraylist but I don't want a new arraylist which contains the uncommon elements. But I want to get my both arraylist only without their common elements.

You could use a Map from String to your object type (I used Obj in order to make a SSCCE).

Assume we are given a list objects and a list strings .

Steps:

  1. Put all objects in a map with their str variable as key
  2. Get all those str variables using map.keySet()
  3. Get all strings that are in objects but not in strings by keys.removeAll(strings)
  4. Get all strings that are in strings but not in objects by strings.removeAll(keys)
  5. Get the objects that correspond to the remaining keys

Note that you need to be careful in steps 3 and 4, because you need to back up one of the collections.

import java.util.*;

public class Test { 
    public static void main(String[] args) throws Exception {
        new Test();
    }

    public Test() {
        List<Obj> objects = new ArrayList<>();
        objects.add(new Obj("a"));
        objects.add(new Obj("b"));
        objects.add(new Obj("c"));

        List<String> strings = new ArrayList<>();
        strings.add("a");
        strings.add("d");
        strings.add("e");

        remove(objects, strings);

        System.out.println(objects);
        System.out.println(strings);
    }

    public void remove(List<Obj> objects, List<String> strings) {
        Map<String, Obj> map = new HashMap<>();
        for (Obj object : objects) {
            map.put(object.str, object);
        }

        Set<String> keys = map.keySet();
        List<String> oldStrings = new ArrayList<>(strings);

        strings.removeAll(keys);
        keys.removeAll(oldStrings);

        objects.clear();
        for (String key: keys) {
            objects.add(map.get(key));
        }       
    }

    public class Obj {  
        public String str;
        public Obj(String str) {
            this.str = str;
        }
        @Override
        public String toString() {
            return str;
        }       
    }
}

Prints:

[b, c]
[d, e]

I will go with some clues for you

Suppose you have two lists one for bean objects namely myBeans and another for filePaths namely filePaths

List<MyBean> beansToRemove = new ArrayList<MyBean>();
List<FilePath> filePathsToRemove = new ArrayList<FilePath>();

for(Bean myBean : myBeans) {
    for(FilePath filePath : filePaths) {
        if(myBean.getfilePath.equals(filePath.getFilePath())) {
            beansToRemove.add(myBean);
            filePathsToRemove.add(filePath);
        }
    }
}

//Now remove filePaths and beans if any

for(Bean myBean : beansToRemove) {
    myBeans.remove(myBean);
}

for(FilePath filePath : filePathsToRemove) {
    filePaths.remove(filePath);
}

it is just a flow to make you clear for what to do; you can further customize it according to your needs.

You can use an outer loop to scan over the Bean objects, and an inner loop to scan over the file paths.

pseudo code:

for (Bean i in beans) {
    for (String p in paths) {
        if (i.path.equals(p)) {
            beansToRemove.add(i);
            pathsToRemove.add(p);
        }
    }
}
beans.removeAll(beansToRemove);
paths.removeAll(pathsToRemove);

I'm not sure if my extra arraylists to track the removed arraylists go against your question or not since the original arrays remain. If you presort both arrays on the path and keep track of the position in each area (not exhaustive search) you can improve it from n2 to nlgn

Rough Java code:

HashSet<String> commonKeys = new HashSet();
for (Share share : shares) {
    commonKeys.add(share.filePath);
}
commonKeys.retainAll(filePaths);
for (Iterator<Share> it = shares.iterator(); it.hasNext(); ) {
    Share share = it.next();
    if (commonKeys.contains(share.filePath)) {
        it.remove();
    }
}
filePaths.removeAll(commonKeys);

This won't be O(N) because remove on an ArrayList is expensive. To get O(N) behavior you either need to create new ArrayList instances, or add the elements you don't want removed to temporary lists, and then clear() and add them back into the original lists.

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