我有一个包含以下字符串的 ArrayList
;
List<String> e = new ArrayList<String>();
e.add("123");
e.add("122");
e.add("125");
e.add("123");
我想检查列表中的重复项并将其从列表中删除。 在这种情况下,我的列表只有两个值,在此示例中它将是值122和125,而两个123将会消失。最好的方法是什么?我考虑使用一个Set,但那只会删除其中一个重复项。在Java 8中,您可以执行:
e.removeIf(s -> Collections.frequency(e, s) > 1);
若不是Java 8,您可以创建一个HashMap<String, Integer>
。如果该字符串已经出现在map中,则将其键值加一,否则将其添加到map中。
例如:
put("123", 1);
现在假设你再次拥有"123",你应该获得该键的计数并将其加一:
put("123", get("aaa") + 1);
现在您可以轻松地在地图上进行迭代,并创建一个新的数组列表,其中键的值小于2。ArrayList
类型,因为removeIf
被重写以在结尾时批量执行所有删除操作。例如,在LinkedList
上它不起作用。 - Paul BoddingtonList::removeIf
是一种简洁的解决方案,但由于需要遍历列表并使用 Collection::frequency
,其时间复杂度为 O(n²)
,我的理解正确吗? - FlownremoveIf
仅增加常数时间。因此,总体复杂度确实为O(n²)。 - MarounMap<String, Long>
来计算出现次数,然后迭代EntrySet
以获取唯一元素,则复杂度为O(2*n) -> O(n)
,我理解的是否正确? - Flown您也可以在Java 8中使用filter
e.stream().filter(s -> Collections.frequency(e, s) == 1).collect(Collectors.toList())
HashMap<String, Integer>
。{"123", 2}
{"122", 1}
{"125", 1}
Map <String,Integer> map = new HashMap<String, Integer>();
for (String s : list){
if (map.get(s) == null){
map.put(s, 1);
}
else {
map.put(s, map.get(s) + 1);
}
}
List<String> newList = new ArrayList<String>();
// Remove from list if there are multiples of them.
for (Map.Entry<String, String> entry : map.entrySet())
{
if(entry.getValue() > 1){
newList.add(entry.getKey());
}
}
list.removeAll(newList);
ArrayList中的解决方案
public static void main(String args[]) throws Exception {
List<String> e = new ArrayList<String>();
List<String> duplicate = new ArrayList<String>();
e.add("123");
e.add("122");
e.add("125");
e.add("123");
for(String str : e){
if(e.indexOf(str) != e.lastIndexOf(str)){
duplicate.add(str);
}
}
for(String str : duplicate){
e.remove(str);
}
for(String str : e){
System.out.println(str);
}
}
List<String> e = new ArrayList<String>();
e.add("123");
e.add("122");
e.add("125");
e.add("123");
e.add("125");
e.add("124");
List<String> sortedList = new ArrayList<String>();
for (String current : e){
if(!sortedList.contains(current)){
sortedList.add(current);
}
else{
sortedList.remove(current);
}
}
e.clear();
e.addAll(sortedList);
使用流的最简单解决方案时间复杂度为O(n^2)
,如果你在包含数百万条目的List
上尝试它们,你将等待很长时间。一个O(n)
的解决方案是:
list = list.stream()
.collect(Collectors.groupingBy(Function.identity(), LinkedHashMap::new, Collectors.counting()))
.entrySet()
.stream()
.filter(e -> e.getValue() == 1)
.map(Map.Entry::getKey)
.collect(Collectors.toList());
Map<String, Integer> map = new LinkedHashMap<>();
for (String s : list)
map.merge(s, 1, Integer::sum);
list = new ArrayList<>();
for (Map.Entry<String, Integer> e : map.entrySet())
if (e.getValue() == 1)
list.add(e.getKey());
O(2*n)
,因此为O(n)
。 - FlownO(n)
。 - Paul BoddingtonO(n^2)
。而我的解决方案并不是最简单的。 - Paul Boddington.collect(groupingBy(identity(), counting()))
。 - Alexis C.Something like this
Set<Object> blackList = new Set<>()
public void add(Object object) {
if (blackList.exists(object)) {
return;
}
boolean notExists = set.add(object);
if (!notExists) {
set.remove(object)
blackList.add(object);
}
}
List<String> duplicateList = new ArrayList<String>();
duplicateList.add("123");
duplicateList.add("122");
duplicateList.add("125");
duplicateList.add("123");
duplicateList.add("127");
duplicateList.add("127");
System.out.println(duplicateList);
Set<String> nonDuplicateList = new TreeSet<String>();
Set<String> duplicateValues = new TreeSet<String>();
if(nonDuplicateList.size()<duplicateList.size()){
for(String s: duplicateList){
if(!nonDuplicateList.add(s)){
duplicateValues.add(s);
}
}
duplicateList.removeAll(duplicateValues);
System.out.println(duplicateList);
System.out.println(duplicateValues);
}
@Test
public void testTrimDupList() {
Collection<String> dups = Lists.newArrayList("123", "122", "125", "123");
dups = removeAll("123", dups);
Assert.assertFalse(dups.contains("123"));
Collection<Integer> dups2 = Lists.newArrayList(123, 122, 125,123);
dups2 = removeAll(123, dups2);
Assert.assertFalse(dups2.contains(123));
}
private <T> Collection<T> removeAll(final T element, Collection<T> collection) {
return Collections2.filter(collection, new Predicate<T>(){
@Override
public boolean apply(T arg0) {
return !element.equals(arg0);
}});
}
再深入思考一下
本页中的大多数其他示例都使用java.util.List API作为基础集合。我不确定是否出于意图,但如果返回的元素必须是List,则可以使用如下指定的另一个中间方法。多态万岁!
@Test
public void testTrimDupListAsCollection() {
Collection<String> dups = Lists.newArrayList("123", "122", "125", "123");
//List used here only to get access to the .contains method for validating behavior.
dups = Lists.newArrayList(removeAll("123", dups));
Assert.assertFalse(dups.contains("123"));
Collection<Integer> dups2 = Lists.newArrayList(123, 122, 125,123);
//List used here only to get access to the .contains method for validating behavior.
dups2 = Lists.newArrayList(removeAll(123, dups2));
Assert.assertFalse(dups2.contains(123));
}
@Test
public void testTrimDupListAsList() {
List<String> dups = Lists.newArrayList("123", "122", "125", "123");
dups = removeAll("123", dups);
Assert.assertFalse(dups.contains("123"));
List<Integer> dups2 = Lists.newArrayList(123, 122, 125,123);
dups2 = removeAll(123, dups2);
Assert.assertFalse(dups2.contains(123));
}
private <T> List<T> removeAll(final T element, List<T> collection) {
return Lists.newArrayList(removeAll(element, (Collection<T>) collection));
}
private <T> Collection<T> removeAll(final T element, Collection<T> collection) {
return Collections2.filter(collection, new Predicate<T>(){
@Override
public boolean apply(T arg0) {
return !element.equals(arg0);
}});
}
Set
不会移除项目,它将防止添加重复的项目。 - Thomas Weller