有没有任何方法可以做到这一点?我在搜索,但找不到任何内容。
另一个问题:我需要这些方法以便过滤文件。有些是 AND
过滤器,有些是 OR
过滤器(就像集合理论中的那样),因此我需要根据所有文件和保存这些文件的联合/交集 ArrayLists 进行筛选。
我应该使用不同的数据结构来保存这些文件吗?是否有其他东西能够提供更好的运行时?
有没有任何方法可以做到这一点?我在搜索,但找不到任何内容。
另一个问题:我需要这些方法以便过滤文件。有些是 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;
}
}
HashSet
来进行交集操作,这样平均情况下的性能将会是O(n),而不是O(n^2)。 - ZongCollection(因此也包括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]
HashSet
替代。 - KosaddAll()
如何对列表进行并集操作;它只是将第二个列表连接到第一个列表的末尾。如果第一个列表已经包含元素,那么并集操作会避免添加该元素。 - dimo414这篇文章有些陈旧,但是在谷歌搜索这个话题时它是第一个弹出来的。
我想要提供一个使用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());
如果有更好/更快的解决方案,请告诉我,但这个解决方案是一个漂亮的一行代码,可以轻松地包含在方法中,而不需要添加不必要的帮助类/方法,并仍然保持可读性。
Set
,然后使用 set 的 contains
方法。并非所有事情都必须使用流来完成。 - dimo414list1.retainAll(list2) - is intersection
使用 removeAll
方法移除集合中的元素,再使用 addAll
方法将需要添加的元素加入集合。
在 collection 的文档中可以找到更多信息(ArrayList 是一个 collection) http://download.oracle.com/javase/1.5.0/docs/api/java/util/Collection.html
retainAll()
和removeAll()
在列表上都是O(n^2)的操作。我们可以做得更好。 - dimo414retainAll
在 {1, 2, 3} 上的结果是 {1, 2, 2, 3}。难道交集不应该是 {1, 2, 3} 吗? - ghchoiCollectionUtils
工具类。CollectionUtils.union(collection1, collection2);
,针对交集使用 CollectionUtils.intersection(collection1, collection2);
。 - Prasannjeet Singh标记的解决方案不是高效的。它的时间复杂度为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;
}
contains()
(如Devenv所建议的)需要O(n + m)时间。排序是不必要的复杂操作,需要O(n log n + m log n + n)时间。尽管这可以简化为O(n log n)时间,但仍然比线性时间更差,并且更加复杂。 - dimo414JAVA 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;
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]
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 对象,则可以修改您的流:
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());
Vector
?自从Java 1.2以后,该类已经不再被推荐使用了。 - dimo414Vector
的时候是用于跨线程交互,但对于这些用例,有更安全的数据结构可供选择。另请参见此问题。在2016年仍在使用Vector
的任何库在我看来都非常可疑。 - dimo414