[英]Intersection and union of ArrayLists in Java
有什么方法可以做到嗎? 我正在尋找但找不到任何東西。
另一個問題:我需要這些方法來過濾文件。 有些是AND
過濾器,有些是OR
過濾器(就像在集合論中一樣),所以我需要根據所有文件和包含這些文件的聯合/相交 ArrayLists 進行過濾。
我應該使用不同的數據結構來保存文件嗎? 還有什么可以提供更好的運行時間的嗎?
這是一個沒有使用任何第三方庫的簡單實現。 與retainAll
、 removeAll
和addAll
相比的主要優點是這些方法不會修改方法的原始列表輸入。
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;
}
}
集合(所以 ArrayList 也是)有:
col.retainAll(otherCol) // for intersection
col.addAll(otherCol) // for union
如果您接受重復,請使用 List 實現,如果您不接受,請使用 Set 實現:
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]
這篇文章相當老了,但它是谷歌搜索該主題時出現的第一個。
我想使用 Java 8 流進行更新(基本上)在一行中做同樣的事情:
List<T> intersect = list1.stream()
.filter(list2::contains)
.collect(Collectors.toList());
List<T> union = Stream.concat(list1.stream(), list2.stream())
.distinct()
.collect(Collectors.toList());
如果有人有更好/更快的解決方案,請告訴我,但這個解決方案是一個很好的襯線,可以很容易地包含在方法中,而無需添加不必要的幫助類/方法,並且仍然保持可讀性。
list1.retainAll(list2) - is intersection
union 將是removeAll
,然后是addAll
。
在集合的文檔中查找更多信息(ArrayList 是一個集合) http://download.oracle.com/javase/1.5.0/docs/api/java/util/Collection.html
您可以使用來自apache commons的CollectionUtils
。
標記的解決方案效率不高。 它的時間復雜度為 O(n^2)。 我們可以做的是對兩個列表進行排序,並執行如下所示的交集算法。
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;
}
這個復雜度為 O(n log n + n),在 O(n log n) 中。 聯合以類似的方式完成。 只需確保對 if-elseif-else 語句進行適當的修改。
如果需要,您也可以使用迭代器(我知道它們在 C++ 中更有效,我不知道這在 Java 中是否也是如此)。
這是一種與流進行交集的方法(請記住,您必須對流使用 java 8):
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());
不同類型列表的示例。 如果您在 foo 和 bar 之間有一個實體,並且您可以從 foo 獲得一個 bar-object,那么您可以修改您的流:
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());
您可以使用 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]
自JAVA 8以來的單行代碼
return concat(a.stream(), b.stream()).collect(toList());
return concat(a.stream(), b.stream()).distinct().collect(toList());
return concat(a.stream(), b.stream()).collect(toSet());
return a.stream().filter(b::contains).collect(toList());
性能:如果集合b
很大而不是 O(1),則通過在return
之前添加 1 行來預先優化過濾器性能:復制到HasSet
( import java.util.Set;
) :
... b = Set.copyOf(b);
return a.stream().distinct().filter(b::contains).collect(toList());
導入靜態 java.util.stream.Stream.concat;
導入靜態 java.util.stream.Collectors.toList;
導入靜態 java.util.stream.Collectors.toSet;
我發現 ListUtils 對於這個用例非常有用。
如果您不想修改現有列表,請使用 org.apache.commons.collections 中的 ListUtils。
ListUtils.intersection(list1, list2)
在 Java 8 中,我使用如下簡單的輔助方法:
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();
}
如果列表中的對象是可散列的(即有一個不錯的 hashCode 和 equals 函數),表之間最快的方法大約是。 size > 20 是為兩個列表中的較大者構造一個 HashSet。
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;
}
}
我也在處理類似的情況並到達這里尋求幫助。 最終找到了我自己的數組解決方案。 ArrayList AbsentDates = new ArrayList(); // 將存儲 Array1-Array2
注意:如果它可以幫助到達此頁面尋求幫助的人,請發布此內容。
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 );
}
基於公共鍵的兩個不同對象列表的交集 - 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());
}
public static <T> Set<T> intersectCollections(Collection<T> col1, Collection<T> col2) {
Set<T> set1, set2;
if (col1 instanceof Set) {
set1 = (Set) col1;
} else {
set1 = new HashSet<>(col1);
}
if (col2 instanceof Set) {
set2 = (Set) col2;
} else {
set2 = new HashSet<>(col2);
}
Set<T> intersection = new HashSet<>(Math.min(set1.size(), set2.size()));
for (T t : set1) {
if (set2.contains(t)) {
intersection.add(t);
}
}
return intersection;
}
JDK8+(可能是最佳性能)
public static <T> Set<T> intersectCollections(Collection<T> col1, Collection<T> col2) {
boolean isCol1Larger = col1.size() > col2.size();
Set<T> largerSet;
Collection<T> smallerCol;
if (isCol1Larger) {
if (col1 instanceof Set) {
largerSet = (Set<T>) col1;
} else {
largerSet = new HashSet<>(col1);
}
smallerCol = col2;
} else {
if (col2 instanceof Set) {
largerSet = (Set<T>) col2;
} else {
largerSet = new HashSet<>(col2);
}
smallerCol = col1;
}
return smallerCol.stream()
.filter(largerSet::contains)
.collect(Collectors.toSet());
}
如果您不關心性能並喜歡較小的代碼,請使用:
col1.stream().filter(col2::contains).collect(Collectors.toList());
首先,我將數組的所有值復制到一個數組中,然后將重復值刪除到數組中。 第 12 行,解釋如果相同的數字出現的時間超過時間,然后將一些額外的垃圾值放入“j”位置。 最后,從頭端遍歷,檢查是否出現相同的垃圾值,然后丟棄。
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]+" ");
}
}
}
經過測試,這是我最好的交叉方法。
與純 HashSet 方法相比,速度更快。 下面的 HashSet 和 HashMap 對於超過 100 萬條記錄的數組具有相似的性能。
至於 Java 8 Stream 方法,對於大於 10k 的數組大小,速度非常慢。
希望這能有所幫助。
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));
}
retainAll() 方法用於查找公共元素..ie;intersection list1.retainAll(list2)
最終解決方案:
//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;
}
如果數字匹配而不是我正在檢查它是否第一次出現,如果數字第一次匹配,則打印並保存到字符串中t 打印,因為由於“indexOf()”條件將是錯誤的。
class Intersection
{
public static void main(String[] args)
{
String s="";
int[] array1 = {1, 2, 5, 5, 8, 9, 7,2,3512451,4,4,5 ,10};
int[] array2 = {1, 0, 6, 15, 6, 5,4, 1,7, 0,5,4,5,2,3,8,5,3512451};
for (int i = 0; i < array1.length; i++)
{
for (int j = 0; j < array2.length; j++)
{
char c=(char)(array1[i]);
if(array1[i] == (array2[j])&&s.indexOf(c)==-1)
{
System.out.println("Common element is : "+(array1[i]));
s+=c;
}
}
}
}
}
如果您在 Sets 中有數據,則可以使用 Guava 的Sets
類。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.