web-dev-qa-db-fra.com

Intersection et union de ArrayLists en Java

Existe-t-il des méthodes pour le faire? Je cherchais mais je n'ai pas pu en trouver.

Autre question: j'ai besoin de ces méthodes pour pouvoir filtrer les fichiers. Certains sont des filtres AND et certains sont des filtres OR (comme dans la théorie des ensembles), je dois donc filtrer en fonction de tous les fichiers et de la liste ArrayLists unite/intersects qui contient ces fichiers.

Devrais-je utiliser une structure de données différente pour contenir les fichiers? Y at-il autre chose qui offrirait une meilleure exécution?

117
yotamoo

Voici une implémentation simple sans utiliser de bibliothèque tierce. Le principal avantage sur retainAll, removeAll et addAll est que ces méthodes ne modifient pas les listes d'origine entrées dans les méthodes.

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 (donc ArrayList également) ont:

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

Utilisez une implémentation de liste si vous acceptez des répétitions, une implémentation de set si vous ne le faites pas:

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

Cet article est assez ancien, mais c’est néanmoins le premier article qui a été publié sur Google lors de la recherche de ce sujet.

Je souhaite effectuer une mise à jour à l'aide de flux Java 8 faisant (en gros) la même chose sur une seule ligne:

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

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

Si quelqu'un a une solution meilleure/plus rapide, faites-le moi savoir, mais cette solution est une doublure Nice one qui peut être facilement incluse dans une méthode sans ajouter de classe/méthode d'assistance inutile tout en préservant la lisibilité. 

57
Fat_FS
list1.retainAll(list2) - is intersection

l'union sera removeAll et ensuite addAll.

Trouvez plus dans la documentation de collection (ArrayList est une collection) http://download.Oracle.com/javase/1.5.0/docs/api/Java/util/Collection.html

32
The GiG

Unions et intersections définies uniquement pour des ensembles, pas de listes. Comme vous l'avez mentionné.

Vérifiez la bibliothèque guava pour les filtres. La goyave fournit également de vrais intersections et des unions

 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

Vous pouvez utiliser CollectionUtils à partir de Apache commons

10
bluefoot

La solution marquée n'est pas efficace. Il a une complexité temporelle O (n ^ 2). Ce que nous pouvons faire est de trier les deux listes et d’exécuter un algorithme d’intersection comme celui présenté ci-dessous. 

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; 
}

Celui-ci a une complexité de O (n log n + n) qui se trouve dans O (n log n). L’union se fait de la même manière. Assurez-vous simplement d’apporter les modifications appropriées aux instructions if-elseif-else. 

Vous pouvez également utiliser des itérateurs si vous le souhaitez (je sais qu'ils sont plus efficaces en C++, je ne sais pas si cela est également vrai en Java). 

8
AJed

Je pense que vous devriez utiliser une Set pour conserver les fichiers si vous voulez faire des intersections et des unions sur eux. Vous pouvez ensuite utiliser Guava 's Sets class pour faire union, intersection et le filtrage par Predicate également. La différence entre ces méthodes et les autres suggestions est que toutes ces méthodes créent paresseux vues de l'union, de l'intersection, etc. des deux ensembles. Apache Commons crée une nouvelle collection et y copie des données. retainAll modifie l'une de vos collections en en supprimant des éléments.

4
ColinD

Voici un moyen d'intersection de flux (souvenez-vous que vous devez utiliser Java 8 pour les flux): 

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());

Un exemple pour les listes avec différents types. Si vous avez une relation entre foo et bar et que vous pouvez obtenir un objet bar de foo, vous pouvez modifier votre flux

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

En Java 8, j'utilise des méthodes d'assistance simples comme celle-ci:

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

Vous pouvez utiliser commons-collections4 CollectionUtils

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

Je travaillais aussi sur une situation similaire et je suis arrivé ici pour chercher de l'aide. J'ai fini par trouver ma propre solution pour les tableaux . ArrayList AbsentDates = new ArrayList (); // va stocker Array1-Array2

Remarque: Publier ceci si cela peut aider quelqu'un qui atteint cette page pour obtenir de l'aide.

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

Si les objets de la liste sont haschables (c'est-à-dire qu'ils ont un hashCode décent et une fonction égale), l'approche la plus rapide entre les tables est d'env. taille> 20 consiste à construire un HashSet pour la plus grande des deux listes.

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

Tout d'abord, je copie toutes les valeurs des tableaux dans un seul tableau, puis je supprime les valeurs en double dans le tableau. Ligne 12, expliquant si le même nombre se produit plus que le temps, puis placez une valeur de déchet supplémentaire dans la position "j". À la fin, effectuez un parcours depuis le début à la fin et vérifiez si la même valeur de garbage apparaît, puis supprimez-la.

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

Après les tests, voici ma meilleure approche d'intersection.

Vitesse plus rapide comparée à l'approche pure HashSet. HashSet et HashMap ci-dessous ont des performances similaires pour les tableaux de plus d'un million d'enregistrements.

En ce qui concerne l'approche Java 8 Stream, la vitesse est assez lente pour une taille de tableau supérieure à 10 Ko.

J'espère que cela peut aider.

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

Solution finale:

//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

Intersection de deux listes d'objets différents basés sur une clé commune - 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