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?
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;
}
}
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]
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é.
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
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)
Vous pouvez utiliser CollectionUtils
à partir de Apache commons .
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).
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.
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());
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();
}
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]
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 );
}
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;
}
}
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]+" ");
}
}
}
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));
}
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;
}
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());
}