Java:比较两个列表,如果其中任何一个包含另一个列表的值,则将两者的所有值都添加到新列表中

时间:2017-11-14 04:18:45

标签: java list arraylist hashmap hashset

我有一个带有String键的HashMap和MyObject值的ArrayList,现在我想创建一个包含所有重叠MyObjects的列表的新列表。

例如:如果ArrayList1包含MyObjectA,MyObjectB,MyObjectC和ArrayList2包含MyObjectA,MyObjectD,MyObjectE,那么我想将MyObjectA-E添加到新列表中,并将所有这些列表放在主列表中。如果任何值重叠,我想基本上将每个ArrayList的值组合成一个新列表。

到目前为止,我只是遍历地图,遍历每个列表,然后再次嵌套迭代,如果有任何值匹配,则在嵌套中对两个ArrayLists执行另一次迭代,将它们添加到不同的列表中,但是这样导致新列表中的重复。

对不起,如果不是很清楚。

有没有人有任何建议或者更好的方法来实现这个目标?

谢谢!

这是我的代码:

public class DetermineOverlaps {

HashMap<String, ArrayList<CustomObject>> pgsPerStMap;

HashSet<HashSet<String>> competingPgs;

public DetermineOverlaps (HashMap<String, ArrayList<CustomObject>> pgsPerStMap2){

    pgsPerStMap = new HashMap<String, ArrayList<CustomObject>>(pgsPerStMap2);

    competingPgs = calculateCompetingPgs();

}

public HashSet<HashSet<String>> calculateCompetingPgs (){

    //This will be the hashset which gets returned from this method
    HashSet<HashSet<String>> competingProdGros = new HashSet<HashSet<String>>();

    //I will iterate over each term (key) within the pgsPerStMap map, which contains search terms | all customObject for that search term
    for (String searchTerm : pgsPerStMap.keySet()){

        //I will iterate over each customObject for the search term
        ArrayList<CustomObject> searchTermsPgs = pgsPerStMap.get(searchTerm);

        for (CustomObject curProdGroup : searchTermsPgs){

            String curProdGroupName = curProdGroup.key;

            //I will store all found matches in this hashset, which I will later put in the competingProdGros map
            HashSet<String> tempPgSet = new HashSet<String>();

            //Compare every other key/value combination of the map to every other key/value combination of the map
            for (String searchTerm2ndLevel : pgsPerStMap.keySet()){
                //Iterate over the customObject
                ArrayList<CustomObject> searchTermsPgsLev2 = pgsPerStMap.get(searchTerm2ndLevel);

                for (CustomObject curProdGroup2ndLevel : searchTermsPgsLev2){

                     String curProdGroupLevel2Name = curProdGroup2ndLevel.key;
                    //If these are different keys, but the same value, i.e. you've got a value which has multiple
                    //overlapping keys, and the temporary hashset doesn't contain the value already
                    //Then add all values from both arraylist<CustomObject> into the temporary hashset...
                    if (!searchTerm2ndLevel.equals(searchTerm) && curProdGroupLevel2Name.equals(curProdGroupName)
                    && !tempPgSet.contains(curProdGroupLevel2Name)){

                        for (CustomObject levelOnePg : searchTermsPgs){

                            String levelOnePgKey = levelOnePg.key;

                            tempPgSet.add(levelOnePgKey);

                        }

                        for (CustomObject levelTwoPg : searchTermsPgsLev2){

                            String levelTwoPgKey = levelTwoPg.key;
                            tempPgSet.add(levelTwoPgKey);

                        }

                    }

                }

            }

            //Add the temporary hashset into the competingProdGros hashset
            if(!competingProdGros.contains(tempPgSet)){competingProdGros.add(tempPgSet);}

        }

    }

    //return the competingprodgros hashset
    return competingProdGros;

}

2 个答案:

答案 0 :(得分:1)

我无法做出你正在尝试做的事情的正面或反面,但我可以给你一些想法来帮助你实现它。

你说你想要一个A-E对象列表,所以我会说你不允许重复。在这种情况下,您可以使用String to Sets的映射来减少主列表的大小

我将给你4个场景:

场景1:您不允许重复,列表是对具有唯一内容的对象的引用

Map<String, Set<MyObject> map = new HashMap<String, Set<MyObject>>();
Set<MyObject> set1 = new LinkedHashSet<MyObject>();
Set<MyObject> set2 = new LinkedHashSet<MyObject>();
MyObject a = new MyObject("A");
MyObject b = new MyObject("B");
MyObject c = new MyObject("C");
MyObject d = new MyObject("D");
MyObject e = new MyObject("E");
set1.add(a);
set1.add(b);
set1.add(c);
set2.add(c);
set2.add(d);
set2.add(e);
set2.removeAll(set1)
set1.addAll(set2);
map.put("Mykey", set1);

这说的是对象在集合中是相同的,因此将在两个集合之间移除。 set1的内容是:

[ "A", "B", "C", "D", "E" ]

场景2:您允许重复,列表是对相同对象的引用。在这里,我猜你想要一对一的删除,所以你循环通过一组交叉点直到为空,然后将列表添加到组合列表中。如果您需要维护列表的值,您可以始终实例化一个新列表并将其传递给列表中的内容

最后一点注意事项:删除增强for循环中树集的元素会导致抛出ConcurrentModificationException

MyObject a = new MyObject("A");
MyObject b = new MyObject("B");
MyObject c = new MyObject("C");
MyObject d = new MyObject("D");
MyObject e = new MyObject("E");
List<CodeTester> l = new ArrayList<CodeTester>();
List<CodeTester> l2 = new ArrayList<CodeTester>();
l.add(a);
l.add(c);
l.add(c);
l.add(b);
l.add(b);
l.add(d);
l2.add(c);
l2.add(d);
l2.add(d);
l2.add(e);
Set<CodeTester> set = new HashSet<CodeTester>(l);
set.retainAll(l2); // get the intersections
while(!set.isEmpty()) {
    l2.remove(0);
    set.retainAll(l2);
}
map.put("myKey", set);

这些内容的输出是:

[ "A", "C", "C", "B", "B", "D", "D", "E" ]

注意&#34; C&#34;的一个实例和&#34; D&#34;被排除在最终名单之外,因为另一个名单有他们

场景3:您不允许重复,但不保证列表元素是对具有唯一内容的对象的引用

如果我不得不猜测我说这是你正在寻找的那个。 这里MyObject使用不同的哈希码/ id实例化新实例。这使得所有MyObject实例都是唯一的,无论内容如何,​​因此如果使用相同的String声明两个MyObject,则默认的Collections操作不会删除/保留它们。要比较内容,您需要实现一些重写方法。然后,您将能够以相同的方式使用上述过程。唯一不同的是用户TreeSet而不是HashSet来调用重写的equals方法然后我们可以实现Comparable或实现Comparator来使用TreeSet并避免它将从其默认的Comparator抛出的ClassCastException。

For Sets强制执行唯一性:

public class MyObject implements Comparable<MyObject>
String s;
Map<String, Set<MyObject> map = new HashMap<String, Set<MyObject>>();
Map<String, List<MyObject> map = new HashMap<String, List<MyObject>>();

public MyObject(String s){
    this.s = s;
}

public void myExample1(){
    Set<MyObject> set1 = new TreeSet<MyObject>();
    Set<MyObject> set2 = new TreeSet<MyObject>();
    MyObject a = new MyObject("A");
    MyObject b = new MyObject("B");
    MyObject c = new MyObject("C");
    MyObject d = new MyObject("D");
    MyObject e = new MyObject("E");
    MyObject b2 = new MyObject(new StringBuilder("F").replace(0, 1, "B").toString());
    MyObject d2 = new MyObject(new StringBuilder("G").replace(0, 1, "D").toString());
    set1.add(a);
    set1.add(b);
    set1.add(c);
    set2.add(b2);
    set2.add(d);
    set2.add(d2);
    set2.add(e);
    set2.removeAll(set1)
    set1.addAll(set2);
    mapS.put("Mykey", set1);
}

public void myExample2(){
    List<MyObject> l = new ArrayList<MyObject>();
    List<MyObject> l2 = new ArrayList<MyObject>();
    l.add(a);
    l.add(c);
    l.add(c);
    l.add(b2);
    l.add(d);
    l2.add(b);
    l2.add(d);
    l2.add(d2);
    l2.add(e);
    Set<MyObject> set = new TreeSet<MyObject>(l);
    set.retainAll(l2); // get the intersections
    Set<MyObject> set2 = new HashSet<MyObject>(set);
    while(!set.isEmpty()) {
        l2.remove(0);
        set.retainAll(l2);
    }
    l.addAll(l2);
    mapL.put("myKey", l);
}

@Override
public int compareTo(MyObject o){
    return s.compareTo(o.getS);
}

public String getS(){
    return s;
}

@Override
public boolean equals(Object o){
    return o instanceof MyObject && compareTo((MyObject) o);
}

}

myExample1输出:

[ "A", "B", "C", "D", "E" ]

使用代码显示唯一性:

[A 865113938, B 1442407170, C 1028566121] [B 1118140819, D 1975012498, E 1808253012]
[A 865113938, B 1442407170, C 1028566121, D 1975012498, E 1808253012]

myExample1输出:

[ "A", "B", "C", "D", "E" ]

使用哈希码来显示唯一性:

[A 865113938, C 1442407170, C 1442407170, B 1028566121, D 1118140819] [B 1975012498, D 1118140819, D 1808253012, E 589431969]
[A 865113938, C 1442407170, C 1442407170, B 1028566121, D 1118140819, E 589431969]

答案 1 :(得分:0)

使用addAll()函数。 例如:ArrayList1.addAll(ArrayList2) 现在ArrayList1将包含所有没有重复的值