我想创建一个方法来过滤掉列表中所有非唯一成员,例如带有输入的列表
3 5 3 8 8 2
会变成
5 2
我有想法尝试以下内容:
private static List<Integer> getUniques(List<Integer> list) {
for (Integer n : list) {
list.remove(n);
if (!list.contains(n)) {
list.add(n);
} else {
while (list.contains(n)) {
list.remove(n);
}
}
}
return list;
}
但是这会引发一个Concurrent Modification异常。我做了一个工作调整:
private static List<Integer> getUniques(List<Integer> list) {
List<Integer> result = new ArrayList<>();
Set<Integer> distinctSet = new HashSet<>();
distinctSet.addAll(list);
result.addAll(list);
for (Integer n : distinctSet) {
result.remove(n);
if (!result.contains(n)) {
result.add(n);
} else {
while (result.contains(n)) {
result.remove(n);
}
}
}
return result;
}
这实现了我想要的,但似乎有点复杂/低效。有没有办法让我以我想到的第一种方式做到这一点?或者另一种更有效的方法?或者我已经基本上使用了最好的方法?
答案 0 :(得分:4)
更好的方法是使用HashMap
标记要保留的元素,然后根据该标记添加。此方法为O(N)
,优于您的解决方案的O(N^2)
(删除可能为O(N)
,具体取决于传入的List实现)。如果这很重要,它当然也会保留原始列表中元素的顺序。
private static List<Integer> getUniques(List<Integer> list) {
HashMap<Integer, Boolean> flagMap = new HashMap<>();
//Total Loop: O(N)
for(Integer i : list){
if(flagMap.containsKey(i)) flagMap.put(i, false); //O(1)
else flagMap.put(i, true); //O(1)
}
ArrayList<Integer> result = new ArrayList<Integer>();
//Total Loop: O(N)
for(Integer i : list){
if(flagMap.get(i)) result.add(i); //O(1)
}
return result;
}
答案 1 :(得分:1)
我建议你从一个方法开始计算一个项目在List
中显示的次数。像
private static <T> int count(List<T> al, T val) {
int r = 0;
for (T t : al) {
if (t.equals(val)) {
r++;
}
}
return r;
}
然后创建一个新的List
返回,并在将count
添加到List
之前检查private static List<Integer> getUniques(List<Integer> list) {
List<Integer> al = new ArrayList<>();
for (Integer n : list) {
if (count(list, n) == 1) {
al.add(n);
}
}
return al;
}
是否为
{{1}}
答案 2 :(得分:1)
使用Java 8,您可以使用流API执行Mshnik正在执行的操作。但是,由于这仍然是一个新的API,您可能需要在工作中谨慎使用它。可读性(由你和你的同行)应该胜过简洁。如果使用Java 8 / stream API不是一个选项,那么Mshnik的解决方案就是我的选择。
List<Integer> uniques =
list.stream().
collect(Collectors.groupingBy(i -> i, Collectors.reducing(0, (a, b) -> a + b))). //Adding all occurances of that number {3->6, 5->5, 8->16, 2->2}
entrySet().stream(). //The above map's entries as a set
filter(e -> e.getValue() == e.getKey()). //Retains {5->5, 2->2}
map(e -> e.getKey()). //Retains {5, 2}
collect(Collectors.<Integer>toList()); //Collects
请注意,虽然每一行可能看起来是列表上的另一个迭代,但这实际上是一个2遍解决方案(第一遍是我们收集地图时,第二遍是我们收集清单时)。
复杂性:预期 O(N) - 如果groupingBy将使用HashMap。