it-swarm.com.de

Schnittmenge und Vereinigung von ArrayLists in Java

Gibt es dafür Methoden? Ich habe gesucht, konnte aber keine finden.

Eine andere Frage: Ich brauche diese Methoden, damit ich Dateien filtern kann. Einige sind AND-Filter und einige sind OR-Filter (wie in der Mengenlehre). Ich muss also nach allen Dateien und den ArrayLists, die diese Dateien enthalten, filtern.

Sollte ich eine andere Datenstruktur für die Dateien verwenden? Gibt es noch etwas, das eine bessere Laufzeit bietet?

117
yotamoo

Hier ist eine einfache Implementierung ohne Verwendung einer Drittanbieter-Bibliothek. Der Hauptvorteil gegenüber retainAll, removeAll und addAll besteht darin, dass diese Methoden die in die Methoden eingegebenen ursprünglichen Listen nicht ändern.

public class Test {

    public static void main(String... args) throws Exception {

        List<String> list1 = new ArrayList<String>(Arrays.asList("A", "B", "C"));
        List<String> list2 = new ArrayList<String>(Arrays.asList("B", "C", "D", "E", "F"));

        System.out.println(new Test().intersection(list1, list2));
        System.out.println(new Test().union(list1, list2));
    }

    public <T> List<T> union(List<T> list1, List<T> list2) {
        Set<T> set = new HashSet<T>();

        set.addAll(list1);
        set.addAll(list2);

        return new ArrayList<T>(set);
    }

    public <T> List<T> intersection(List<T> list1, List<T> list2) {
        List<T> list = new ArrayList<T>();

        for (T t : list1) {
            if(list2.contains(t)) {
                list.add(t);
            }
        }

        return list;
    }
}
110
adarshr

Collection (also auch ArrayList) haben:

col.retainAll(otherCol) // for intersection
col.addAll(otherCol) // for union

Verwenden Sie eine List-Implementierung, wenn Sie Wiederholungen akzeptieren, eine Set-Implementierung, wenn Sie nicht

Collection<String> col1 = new ArrayList<String>(); // {a, b, c}
// Collection<String> col1 = new TreeSet<String>();
col1.add("a");
col1.add("b");
col1.add("c");

Collection<String> col2 = new ArrayList<String>(); // {b, c, d, e}
// Collection<String> col2 = new TreeSet<String>();
col2.add("b");
col2.add("c");
col2.add("d");
col2.add("e");

col1.addAll(col2);
System.out.println(col1); 
//output for ArrayList: [a, b, c, b, c, d, e]
//output for TreeSet: [a, b, c, d, e]
113
smas

Dieser Beitrag ist ziemlich alt, aber trotzdem war er der erste, der bei Google auftauchte, als er nach diesem Thema suchte.

Ich möchte ein Update mit Java 8-Streams durchführen, wobei (im Wesentlichen) dasselbe in einer einzigen Zeile erfolgt:

List<T> intersect = list1.stream()
    .filter(list2::contains)
    .collect(Collectors.toList());

List<T> union = Stream.concat(list1.stream(), list2.stream())
    .distinct()
    .collect(Collectors.toList());

Wenn jemand eine bessere/schnellere Lösung hat, lassen Sie es mich wissen, aber diese Lösung ist ein Nice-Liner, der leicht in eine Methode eingefügt werden kann, ohne eine unnötige Hilfsklasse/-methode hinzuzufügen und trotzdem die Lesbarkeit zu erhalten. 

57
Fat_FS
list1.retainAll(list2) - is intersection

union wird removeAll und dann addAll sein.

Weitere Informationen finden Sie in der Dokumentation der Sammlung (ArrayList ist eine Sammlung) http://download.Oracle.com/javase/1.5.0/docs/api/Java/util/Collection.html

32
The GiG

Vereinigungen und Schnittpunkte, die nur für Mengen definiert sind, nicht für Listen. Wie du erwähnt hast.

Überprüfen Sie guava library auf Filter. Auch bietet Guave echte Kreuzungen und Vereinigungen

 static <E> Sets.SetView<E >union(Set<? extends E> set1, Set<? extends E> set2)
 static <E> Sets.SetView<E> intersection(Set<E> set1, Set<?> set2)
17
Stan Kurilin

Sie können CollectionUtils von Apache commons verwenden. 

10
bluefoot

Die markierte Lösung ist nicht effizient. Es hat eine O (n ^ 2) -Komplexität. Was wir tun können, ist, beide Listen zu sortieren und einen Schnittalgorithmus wie den folgenden auszuführen. 

private  static ArrayList<Integer> interesect(ArrayList<Integer> f, ArrayList<Integer> s) { 
    ArrayList<Integer> res = new ArrayList<Integer>();

    int i = 0, j = 0; 
    while (i != f.size() && j != s.size()) { 

        if (f.get(i) < s.get(j)) {
            i ++;
        } else if (f.get(i) > s.get(j)) { 
            j ++;
        } else { 
            res.add(f.get(i)); 
            i ++;  j ++;
        }
    }


    return res; 
}

Dieser hat eine Komplexität von O (n log n + n), die in O (n log n) liegt. .__ Die Vereinigung geschieht auf ähnliche Weise. Stellen Sie einfach sicher, dass Sie die entsprechenden Änderungen an den if-elseif-else-Anweisungen vornehmen. 

Sie können auch Iteratoren verwenden, wenn Sie möchten (ich weiß, dass sie in C++ effizienter sind, ich weiß nicht, ob dies auch in Java zutrifft). 

8
AJed

Ich denke, Sie sollten eine Set verwenden, um die Dateien zu speichern, wenn Sie sie schneiden und vereinigen möchten. Dann können Sie Guava 's Sets class verwenden, um union, intersection zu tun und auch nach einer Predicate zu filtern. Der Unterschied zwischen diesen Methoden und den anderen Vorschlägen besteht darin, dass alle diese Methoden Lazy views der Vereinigung, Schnittmenge usw. der beiden Mengen erstellen. Apache Commons erstellt eine neue Sammlung und kopiert Daten in diese. retainAll ändert eine Ihrer Sammlungen, indem Elemente daraus entfernt werden.

4
ColinD

So erstellen Sie eine Kreuzung mit Streams (Denken Sie daran, dass Sie Java 8 für Streams verwenden müssen): 

List<foo> fooList1 = new ArrayList<>(Arrays.asList(new foo(), new foo()));
List<foo> fooList2 = new ArrayList<>(Arrays.asList(new foo(), new foo()));
fooList1.stream().filter(f -> fooList2.contains(f)).collect(Collectors.toList());

Ein Beispiel für Listen mit unterschiedlichen Typen. Wenn Sie eine Beziehung zwischen foo und bar haben und Sie können ein bar-Objekt von foo erhalten, können Sie Ihren Stream ändern:

List<foo> fooList = new ArrayList<>(Arrays.asList(new foo(), new foo()));
List<bar> barList = new ArrayList<>(Arrays.asList(new bar(), new bar()));

fooList.stream().filter(f -> barList.contains(f.getBar()).collect(Collectors.toList());
4
Deutro
  • retainAll ändert Ihre Liste
  • Guava hat keine APIs für List (nur für Set)

Ich fand ListUtils für diesen Anwendungsfall sehr nützlich.

Verwenden Sie ListUtils aus org.Apache.commons.collections, wenn Sie die vorhandene Liste nicht ändern möchten.

ListUtils.intersection(list1, list2)

3
Bala

In Java 8 verwende ich einfache Hilfsmethoden wie diese:

public static <T> Collection<T> getIntersection(Collection<T> coll1, Collection<T> coll2){
    return Stream.concat(coll1.stream(), coll2.stream())
            .filter(coll1::contains)
            .filter(coll2::contains)
            .collect(Collectors.toSet());
}

public static <T> Collection<T> getMinus(Collection<T> coll1, Collection<T> coll2){
    return coll1.stream().filter(not(coll2::contains)).collect(Collectors.toSet());
}

public static <T> Predicate<T> not(Predicate<T> t) {
    return t.negate();
}
2
Pascalius

Sie können commons-collection4 CollectionUtils verwenden.

Collection<Integer> collection1 = Arrays.asList(1, 2, 4, 5, 7, 8);
Collection<Integer> collection2 = Arrays.asList(2, 3, 4, 6, 8);

Collection<Integer> intersection = CollectionUtils.intersection(collection1, collection2);
System.out.println(intersection); // [2, 4, 8]

Collection<Integer> union = CollectionUtils.union(collection1, collection2);
System.out.println(union); // [1, 2, 3, 4, 5, 6, 7, 8]

Collection<Integer> subtract = CollectionUtils.subtract(collection1, collection2);
System.out.println(subtract); // [1, 5, 7]
1
xxg

Ich arbeitete auch an einer ähnlichen Situation und erreichte hier auf der Suche nach Hilfe. Am Ende fand ich meine eigene Lösung für Arrays . ArrayList AbsentDates = new ArrayList (); // speichert Array1-Array2

Hinweis: Wenn Sie dies veröffentlichen, kann dies jemandem helfen, der auf dieser Seite Hilfe benötigt.

ArrayList<String> AbsentDates = new ArrayList<String>();//This Array will store difference
      public void AbsentDays() {
            findDates("April", "2017");//Array one with dates in Month April 2017
            findPresentDays();//Array two carrying some dates which are subset of Dates in Month April 2017

            for (int i = 0; i < Dates.size(); i++) {

                for (int j = 0; j < PresentDates.size(); j++) {

                    if (Dates.get(i).equals(PresentDates.get(j))) {

                        Dates.remove(i);
                    }               

                }              
                AbsentDates = Dates;   
            }
            System.out.println(AbsentDates );
        }
1
Shubham Pandey

Wenn die Objekte in der Liste hashierbar sind (d. H. Einen anständigen Hash-Code und eine Equals-Funktion haben), ist der schnellste Ansatz zwischen den Tabellen ca. size> 20 dient dazu, ein HashSet für die größere der beiden Listen zu erstellen.

public static <T> ArrayList<T> intersection(Collection<T> a, Collection<T> b) {
    if (b.size() > a.size()) {
        return intersection(b, a);
    } else {
        if (b.size() > 20 && !(a instanceof HashSet)) {
            a = new HashSet(a);
        }
        ArrayList<T> result = new ArrayList();
        for (T objb : b) {
            if (a.contains(objb)) {
                result.add(objb);
            }
        }
        return result;
    }
}
1
Jeroen Vuurens

Zuerst kopiere ich alle Werte von Arrays in ein einzelnes Array und entferne dann doppelte Werte in das Array. Zeile 12, die erläutert, wenn dieselbe Anzahl mehr als die Zeit auftritt, dann wird ein zusätzlicher Abfallwert in die Position "j" gesetzt. Fahren Sie am Ende von Anfang bis Ende, und prüfen Sie, ob derselbe Müllwert auftritt, und verwerfen Sie ihn.

public class Union {
public static void main(String[] args){

    int arr1[]={1,3,3,2,4,2,3,3,5,2,1,99};
    int arr2[]={1,3,2,1,3,2,4,6,3,4};
    int arr3[]=new int[arr1.length+arr2.length];

    for(int i=0;i<arr1.length;i++)
        arr3[i]=arr1[i];

    for(int i=0;i<arr2.length;i++)
        arr3[arr1.length+i]=arr2[i];
    System.out.println(Arrays.toString(arr3));

    for(int i=0;i<arr3.length;i++)
    {
        for(int j=i+1;j<arr3.length;j++)
        {
            if(arr3[i]==arr3[j])
                arr3[j]=99999999;          //line  12
        }
    }
    for(int i=0;i<arr3.length;i++)
    {
        if(arr3[i]!=99999999)
            System.out.print(arr3[i]+" ");
    }
}   
}
0
Ashutosh

Nach dem Test ist hier mein bester Schnittpunktansatz.

Schnellere Geschwindigkeit im Vergleich zum reinen HashSet-Ansatz. HashSet und HashMap haben eine ähnliche Leistung für Arrays mit mehr als 1 Million Datensätzen.

In Bezug auf den Java 8 Stream-Ansatz ist die Geschwindigkeit bei einer Arraygröße von mehr als 10 KB ziemlich niedrig.

Hoffe das kann helfen.

public static List<String> hashMapIntersection(List<String> target, List<String> support) {
    List<String> r = new ArrayList<String>();
    Map<String, Integer> map = new HashMap<String, Integer>();
    for (String s : support) {
        map.put(s, 0);
    }
    for (String s : target) {
        if (map.containsKey(s)) {
            r.add(s);
        }
    }
    return r;
}
public static List<String> hashSetIntersection(List<String> a, List<String> b) {
    Long start = System.currentTimeMillis();

    List<String> r = new ArrayList<String>();
    Set<String> set = new HashSet<String>(b);

    for (String s : a) {
        if (set.contains(s)) {
            r.add(s);
        }
    }
    print("intersection:" + r.size() + "-" + String.valueOf(System.currentTimeMillis() - start));
    return r;
}

public static void union(List<String> a, List<String> b) {
    Long start = System.currentTimeMillis();
    Set<String> r= new HashSet<String>(a);
    r.addAll(b);
    print("union:" + r.size() + "-" + String.valueOf(System.currentTimeMillis() - start));
}
0
Dilabeing

Endgültige Lösung:

//all sorted items from both
public <T> List<T> getListReunion(List<T> list1, List<T> list2) {
    Set<T> set = new HashSet<T>();
    set.addAll(list1);
    set.addAll(list2);
    return new ArrayList<T>(set);
}

//common items from both
public <T> List<T> getListIntersection(List<T> list1, List<T> list2) {
    list1.retainAll(list2);
    return list1;
}

//common items from list1 not present in list2
public <T> List<T> getListDifference(List<T> list1, List<T> list2) {
    list1.removeAll(list2);
    return list1;
}
0
Choletski

Schnittpunkt zweier Listen unterschiedlicher Objekte basierend auf dem gemeinsamen Schlüssel - Java 8

 private List<User> intersection(List<User> users, List<OtherUser> list) {

        return list.stream()
                .flatMap(OtherUser -> users.stream()
                        .filter(user -> user.getId()
                                .equalsIgnoreCase(OtherUser.getId())))
                .collect(Collectors.toList());
    }
0
Niraj Sonawane