识别列表中的重复项


118

我有一个整数类型的列表,例如:

[1, 1, 2, 3, 3, 3]

我想要一种返回所有重复项的方法,例如:

[1, 3]

做这个的最好方式是什么?


2
输入列表是否保证可以排序(如您的示例所示)?
NPE

7
对列表进行排序,然后遍历,保留当前值和先前值。如果当前==之前,则有重复项。
mcfinnigan

不,列表不一定要排序。
最新鲜的

Answers:


183

该方法addSet返回一个布尔值是否已经存在(true,如果不存在的话,假的,如果它已经存在,请参阅设置文档)。

因此,只需遍历所有值即可:

public Set<Integer> findDuplicates(List<Integer> listContainingDuplicates)
{ 
  final Set<Integer> setToReturn = new HashSet<>(); 
  final Set<Integer> set1 = new HashSet<>();

  for (Integer yourInt : listContainingDuplicates)
  {
   if (!set1.add(yourInt))
   {
    setToReturn.add(yourInt);
   }
  }
  return setToReturn;
}

1
为什么要设置setToReturn?您不仅可以使用set1.add(yourInt)并返回set1吗?
菲尔(Phil)

3
对,就是这样。但是,当一个元素在指定列表中仅出现一次时,该元素也会被添加。看问题中的示例:我的解决方案将返回[1,3],因为将数字2插入set1而不是setToReturn中。您的解决方案将返回[1,2,3](这不是
必需

1
我建议您使用for (Integer yourInt,以避免不必要的装箱和拆箱,尤其是因为您的输入已经包含Integers时。
Hosam Aly

1
@JonasThelemann集合的整个想法是它不能包含重复项。因此:无论您多久添加3个,它最终都只会出现一次。
leifg

1
顺便说一句,如果HashSet您还必须考虑负载系数,例如,当您将初始容量指定为时100,因为您要添加该数量的元素,则将其舍入为下一个2的幂128,这意味着默认负载因子为0.75f,调整大小阈值为96,因此添加100元素之前将进行调整大小。幸运的是,调整大小不再那么昂贵。对于最新的JRE,调整大小不再需要重新散列,元素只是根据相关位在其两个可能的结果位置之间分配。
霍尔格'18

50

我也需要一个解决方案。我使用了leifg的解决方案并使之通用。

private <T> Set<T> findDuplicates(Collection<T> collection) {

    Set<T> duplicates = new LinkedHashSet<>();
    Set<T> uniques = new HashSet<>();

    for(T t : collection) {
        if(!uniques.add(t)) {
            duplicates.add(t);
        }
    }

    return duplicates;
}

1
我知道这是3年后的事,但是为什么要使用LinkedHashedSet,即为什么要关心订单?
Ahmad Ragab

4
@AhmadRagab,您是对的,除非您关心重复的发现顺序(我认为我当时是这样做的),否则不需要LinkedHashSet
John Strickler

感谢您的跟进!
Ahmad Ragab

如果您有太多的输入数据,想要使用这种最佳解决方案(而不是对输入进行排序),则还需要预分配HashSet()对象的大小。如果没有预分配,则在插入HashSet()时不会获得O(1)插入时间。这是因为内部哈希数组会反复调整大小。然后,插入的平均时间为O(log N)。这意味着处理所有N个项目(如果可能是O(N)则变为O(N log N))。
johnstosh

39

我采用了约翰·斯特里克勒(John Strickler)的解决方案,并对其进行了重新制作,以使用JDK8中引入的流API:

private <T> Set<T> findDuplicates(Collection<T> collection) {
    Set<T> uniques = new HashSet<>();
    return collection.stream()
        .filter(e -> !uniques.add(e))
        .collect(Collectors.toSet());
}

3
这很难读,不是吗?您在流操作中正在产生副作用,这使得很难进行推理。但这只是我在思考功能样式。这很简洁,虽然可能是最短的方法;)。
froginvasion

对于大型列表,您可以使它在多个线程上并行执行?
johnstosh

@froginvasion内置distinct()方法也是有状态的。不能想到有效的(O(n))无状态操作。
wilmol

18

这是在Java 8中使用Streams的解决方案

// lets assume the original list is filled with {1,1,2,3,6,3,8,7}
List<String> original = new ArrayList<>();
List<String> result = new ArrayList<>();

您只需查看该对象的频率是否在列表中不止一次。然后调用.distinct()以在结果中仅包含唯一元素

result = original.stream()
    .filter(e -> Collections.frequency(original, e) > 1)
    .distinct()
    .collect(Collectors.toList());
// returns {1,3}
// returns only numbers which occur more than once

result = original.stream()
    .filter(e -> Collections.frequency(original, e) == 1)
    .collect(Collectors.toList());
// returns {2,6,8,7}
// returns numbers which occur only once

result = original.stream()
    .distinct()
    .collect(Collectors.toList());
// returns {1,2,3,6,8,7}
// returns the list without duplicates

1
就可读性而言,这很好,但是对性能却真的很不利。Collections::frequency是O(n)。它需要遍历整个集合才能找到某项商品的出现频率。我们对集合中的每个项目都调用一次,这就是这些片段O(n^2)。您会注意到,除了几个元素之外,任何其他集合中的区别。我永远不会在实际代码中使用它。
帕万

12

Java 8基本解决方案:

List duplicates =    
list.stream().collect(Collectors.groupingBy(Function.identity()))
    .entrySet()
    .stream()
    .filter(e -> e.getValue().size() > 1)
    .map(Map.Entry::getKey)
    .collect(Collectors.toList());

输入列表将转换为地图(按相同值分组)。然后用独特的值映射的值“已删除”然后映射使用密钥,那么列表的列表转换为一个列表
بلالالمصمودي

漂亮而又快速的解决方案,可以直接修改为对特定项目的吸气剂进行过滤
arberg,

11
int[] nums =  new int[] {1, 1, 2, 3, 3, 3};
Arrays.sort(nums);
for (int i = 0; i < nums.length-1; i++) {

    if (nums[i] == nums[i+1]) {
        System.out.println("duplicate item "+nums[i+1]+" at Location"+(i+1) );
    }

}

显然,您可以对它们进行任何操作(即放入Set中以获取唯一的重复值列表),而不用打印...这也具有记录重复项位置的好处。


7

在Java 8上使用Guava

private Set<Integer> findDuplicates(List<Integer> input) {
    // Linked* preserves insertion order so the returned Sets iteration order is somewhat like the original list
    LinkedHashMultiset<Integer> duplicates = LinkedHashMultiset.create(input);

    // Remove all entries with a count of 1
    duplicates.entrySet().removeIf(entry -> entry.getCount() == 1);

    return duplicates.elementSet();
}

7

这也适用:

public static Set<Integer> findDuplicates(List<Integer> input) {
    List<Integer> copy = new ArrayList<Integer>(input);
    for (Integer value : new HashSet<Integer>(input)) {
        copy.remove(value);
    }
    return new HashSet<Integer>(copy);
}

它可以工作,但是速度很慢,因为在数组列表上调用remove()是线性搜索。
johnstosh

真正。请注意,如果您的输入包含许多重复项,那么与只有少数重复项的情况相比,性能影响会较小。
亚德里亚·科斯特

6

您可以使用如下形式:

List<Integer> newList = new ArrayList<Integer>();
for(int i : yourOldList)
{
    yourOldList.remove(i);
    if(yourOldList.contains(i) && !newList.contains(i)) newList.add(i);
}

2
在此处使用列表的效果很差
Alexander Farber11年

2
而且不要让我开始在int这里使用变量类型。这意味着对于每个单次迭代,一个Integer被取消装箱一次,而一个int被装箱四次!
肖恩·帕特里克·弗洛伊德

1
我认为当您尝试在列表上进行迭代时从列表中删除元素时,您很容易获得ConcurrentModificationException
Jad B. 2014年

1
这是100%ConcurrentModificationException,因为您遍历了一个列表并即时删除了元素。
theo231022 '16

5

兰巴斯可能是一个解决方案

Integer[] nums =  new Integer[] {1, 1, 2, 3, 3, 3};
List<Integer> list = Arrays.asList(nums);

List<Integer> dps = list.stream().distinct().filter(entry -> Collections.frequency(list, entry) > 1).collect(Collectors.toList());

1
可以,但是它为每个条目运行Collections.frequency,因此速度很慢。
arberg

4

使用MultiMap将每个值存储为键/值集。然后遍历键并找到具有多个值的键。


3

如果您使用Eclipse Collections,那么它将起作用:

MutableList<Integer> list = Lists.mutable.with(1, 1, 2, 3, 3, 3);
Set<Integer> dupes = list.toBag().selectByOccurrences(i -> i > 1).toSet();
Assert.assertEquals(Sets.mutable.with(1, 3), dupes);

更新:从Eclipse Collections 9.2开始,您现在可以使用selectDuplicates

MutableList<Integer> list = Lists.mutable.with(1, 1, 2, 3, 3, 3);
Set<Integer> dupes = list.toBag().selectDuplicates().toSet();
Assert.assertEquals(Sets.mutable.with(1, 3), dupes);

您还可以使用原始集合来完成此任务:

IntList list = IntLists.mutable.with(1, 1, 2, 3, 3, 3);
IntSet dupes = list.toBag().selectDuplicates().toSet();
Assert.assertEquals(IntSets.mutable.with(1, 3), dupes);

注意:我是Eclipse Collections的提交者。


2
public class practicese {
       public static void main(String[] args) {   

           List<Integer> listOf = new ArrayList<Integer>();
           listOf.add(3);
           listOf.add(1);
           listOf.add(2);
           listOf.add(3);
           listOf.add(3);
           listOf.add(2);
           listOf.add(1);

           List<Integer> tempList = new ArrayList<Integer>();
           for(Integer obj:listOf){
                if(!tempList.contains(obj)){
                    tempList.add(obj);

                }
            }
            System.out.println(tempList);

    }

}

我喜欢这个答案,只需要添加一个else即可将重复项保存在另一个列表中。谢谢
Tiago Machado

2

与此处的某些答案类似,但是如果您要基于某些属性查找重复项,请执行以下操作:

  public static <T, R> Set<R> findDuplicates(Collection<? extends T> collection, Function<? super T, ? extends R> mapper) {
    Set<R> uniques = new HashSet<>();
    return collection.stream()
        .map(mapper)
        .filter(e -> !uniques.add(e))
        .collect(toSet());
  }

1

创建一个Map<Integer,Integer>,对列表进行迭代,如果元素在地图中,则增加其值,否则使用key = 1
将其添加到地图中,对地图进行迭代,然后将key> = 2的所有元素添加到列表中

public static void main(String[] args) {
        List<Integer> list = new LinkedList<Integer>();
        list.add(1);
        list.add(1);
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(3);
        Map<Integer,Integer> map = new HashMap<Integer, Integer>();
        for (Integer x : list) { 
            Integer val = map.get(x);
            if (val == null) { 
                map.put(x,1);
            } else {
                map.remove(x);
                map.put(x,val+1);
            }
        }
        List<Integer> result = new LinkedList<Integer>();
        for (Entry<Integer, Integer> entry : map.entrySet()) {
            if (entry.getValue() > 1) {
                result.add(entry.getKey());
            }
        }
        for (Integer x : result) { 
            System.out.println(x);
        }

    }

很好 如果您需要知道有多少重复,这是最好的解决方案。一些注意事项:(1)在执行put()之前不需要调用remove()。(2)您可以从数组而不是使用重复的add()调用来设置LinkedList。(3)当val!= null时,您可以立即将x添加到结果中。结果可能是一个集合或一个列表,具体取决于您是否要保留重复项的数量。
johnstosh

1

最佳答案的紧凑生成版本,还添加了空支票和预分配的Set大小:

public static final <T> Set<T> findDuplicates(final List<T> listWhichMayHaveDuplicates) {
    final Set<T> duplicates = new HashSet<>();
    final int listSize = listWhichMayHaveDuplicates.size();
    if (listSize > 0) {
      final Set<T> tempSet = new HashSet<>(listSize);
      for (final T element : listWhichMayHaveDuplicates) {
        if (!tempSet.add(element)) {
          duplicates.add(element);
        }
      }
    }
    return duplicates;
  }

您需要零位检查吗?新的HashSet <>(0)是否会返回明智的空集?
johnstosh

@johnstosh此代码可以简化,但是检查零允许仅在必要时使用tempSetwith 初始化listSize。这是次要的优化,但我喜欢。
Christophe Roussy

1

我接受了塞巴斯蒂安的回答,并在其中添加了keyExtractor-

    private <U, T> Set<T> findDuplicates(Collection<T> collection, Function<? super T,? extends U> keyExtractor) {
        Map<U, T> uniques = new HashMap<>(); // maps unique keys to corresponding values
        return collection.stream()
            .filter(e -> uniques.put(keyExtractor.apply(e), e) != null)
            .collect(Collectors.toSet());
    }

1

线程安全的替代方案是这样的:

/**
 * Returns all duplicates that are in the list as a new {@link Set} thread-safe.
 * <p>
 * Usually the Set will contain only the last duplicate, however the decision
 * what elements are equal depends on the implementation of the {@link List}. An
 * exotic implementation of {@link List} might decide two elements are "equal",
 * in this case multiple duplicates might be returned.
 * 
 * @param <X>  The type of element to compare.
 * @param list The list that contains the elements, never <code>null</code>.
 * @return A set of all duplicates in the list. Returns only the last duplicate.
 */
public <X extends Object> Set<X> findDuplicates(List<X> list) {
    Set<X> dups = new LinkedHashSet<>(list.size());
    synchronized (list) {
        for (X x : list) {
            if (list.indexOf(x) != list.lastIndexOf(x)) {
                dups.add(x);
            }
        }
    }
    return dups;
}

0

尝试此操作以查找list中的重复项:

ArrayList<String> arrayList1 = new ArrayList<String>(); 

arrayList1.add("A"); 
arrayList1.add("A"); 
arrayList1.add("B"); 
arrayList1.add("B"); 
arrayList1.add("B"); 
arrayList1.add("C"); 

for (int x=0; x< arrayList1.size(); x++) 
{ 
System.out.println("arrayList1 :"+arrayList1.get(x)); 
} 
Set s=new TreeSet(); 
s.addAll(arrayList1); 
Iterator it=s.iterator(); 
while (it.hasNext()) 
{ 
System.out.println("Set :"+(String)it.next()); 
} 

是的,这找到了集合,但是没有找到重复项的列表或集合。
johnstosh

0

这应该适用于已排序和未排序。

public void testFindDuplicates() {

    List<Integer> list = new ArrayList<Integer>();
    list.add(1);
    list.add(1);
    list.add(2);
    list.add(3);
    list.add(3);
    list.add(3);

    Set<Integer> result = new HashSet<Integer>();
    int currentIndex = 0;
    for (Integer i : list) {
        if (!result.contains(i) && list.subList(currentIndex + 1, list.size()).contains(i)) {
            result.add(i);
        }
        currentIndex++;
    }
    assertEquals(2, result.size());
    assertTrue(result.contains(1));
    assertTrue(result.contains(3));
}

在ArrayList的subList上调用contains()非常昂贵,因为它是线性搜索。因此,这对于10个项目来说是可以的,但对于1000万个项目来说则不是。
johnstosh

0

这是功能技术大放异彩的问题。例如,与最佳命令式Java解决方案相比,以下F#解决方案既清晰又易于出错(并且我每天都使用Java和F#进行工作)。

[1;1;2;3;3;3] 
|> Seq.countBy id 
|> Seq.choose (fun (key,count) -> if count > 1 then Some(key) else None)

当然,这个问题是关于Java的。因此,我的建议是采用一个将Java功能性功能引入库中。例如,可以使用我自己的库来解决此问题,如下所示(还有其他一些值得一看的东西):

Seq.of(1,1,2,3,3,3)
.groupBy(new Func1<Integer,Integer>() {
    public Integer call(Integer key) {
        return key;
    }
}).filter(new Predicate<Grouping<Integer,Integer>>() {
   public Boolean call(Grouping<Integer, Integer> grouping) {
        return grouping.getGrouping().count() > 1;
   }
}).map(new Func1<Grouping<Integer,Integer>,Integer>() {
    public Integer call(Grouping<Integer, Integer> grouping) {
        return grouping.getKey();
    }
});

然后您会看到Java实际上仍然吸引着函数式编程。如此简单的问题,以至于很难用Java表达出来。
froginvasion

0
public class DuplicatesWithOutCollection {

    public static void main(String[] args) {

        int[] arr = new int[] { 2, 3, 4, 6, 6, 8, 10, 10, 10, 11, 12, 12 };

        boolean flag = false;
        int k = 1;
        while (k == 1) {

            arr = removeDuplicate(arr);
            flag = checkDuplicate(arr, flag);
            if (flag) {
                k = 1;
            } else {
                k = 0;
            }

        }

    }

    private static boolean checkDuplicate(int[] arr, boolean flag) {
        int i = 0;

        while (i < arr.length - 1) {

            if (arr[i] == arr[i + 1]) {

                flag = true;

            } else {
                flag = false;
            }
            i++;

        }

        return flag;
    }

    private static int[] removeDuplicate(int[] arr) {

        int i = 0, j = 0;
        int[] temp = new int[arr.length];
        while (i < arr.length - 1) {

            if (arr[i] == arr[i + 1]) {

                temp[j] = arr[i + 1];
                i = i + 2;

            } else {

                temp[j] = arr[i];
                i = i + 1;

                if (i == arr.length - 1) {
                    temp[j + 1] = arr[i + 1];
                    break;
                }

            }
            j++;

        }
        System.out.println();
        return temp;
    }

}

不使用Collection类实现。但是在循环中需要很少的改进。提供自愿帮助。上述输出看起来像-> 2 3 4 6 8 10 11 12
Samrat Roy

为了使此操作在更短的时间内执行,您需要使用基于哈希的数据结构来跟踪重复项。这就是为什么您看到使用HashSet()的其他解决方案的原因-它内置于Java中。
johnstosh

@johnstosh是的,我知道这一点,但是我想在不使用收藏的情况下做到这一点,这就是我在评论中提到的原因。如您所见,我在2017年2月之前发表了评论,[有些技术根本不需要使用收藏[时间复杂度更低] 。geeksforgeeks.org/…。我在不了解DS和Algo惯例的情况下尝试了该程序。因此,您不必为此而投票。
Samrat Roy

0
import java.util.Scanner;

public class OnlyDuplicates {
    public static void main(String[] args) {
        System.out.print(" Enter a set of 10 numbers: ");
        int[] numbers = new int[10];
        Scanner input = new Scanner(System.in);
        for (int i = 0; i < numbers.length; i++) {
            numbers[i] = input.nextInt();
        }
        numbers = onlyDuplicates(numbers);
        System.out.print(" The numbers are: ");
        for (int i = 0; i < numbers.length; i++) {
            System.out.print(numbers[i] + "");
        }
    }

    public static int[] onlyDuplicates(int[] list) {
        boolean flag = true;
        int[] array = new int[0];
        array = add2Array(array, list[0]);
        for (int i = 0; i < list.length; i++) {
            for (int j = 0; j < array.length; j++) {
                if (list[i] == array[j]) {
                    flag = false;
                    break;
                }
            }
            if (flag) {
                array = add2Array(array, list[i]);
            }
            flag = true;
        }
        return array;
    }
    // Copy numbers1 to numbers2
    // If the length of numbers2 is less then numbers2, return false
    public static boolean copyArray(int[] source, int[] dest) {
        if (source.length > dest.length) {
            return false;
        }

        for (int i = 0; i < source.length; i++) {
            dest[i] = source[i];
        }
        return true;
    }
    // Increase array size by one and add integer to the end of the array
    public static int[] add2Array(int[] source, int data) {
        int[] dest = new int[source.length + 1];
        copyArray(source, dest);
        dest[source.length] = data;
        return dest;
    }
}

我需要为此做些什么才能返回重复项?
布伦登

这应该作为一个新问题提出。
willaien

0

这将是查找重复值的好方法,而无需使用Set。

public static <T> List<T> findDuplicates(List<T> list){

List<T> nonDistinctElements = new ArrayList<>();

  for(T s : list)
    if(list.indexOf(s) != list.lastIndexOf(s))
      if(!nonDistinctElements.contains(s))
        nonDistinctElements.add(s);

  return nonDistinctElements;
}

并说,您想要一个可以返回不同列表的方法,即,如果传递的列表中元素多次出现,那么您将获得一个包含不同元素的列表。

public static <T> void distinctList(List<T> list){

List<T> nonDistinctElements = new ArrayList<>();
for(T s : list)
  if(list.indexOf(s) != list.lastIndexOf(s))
    nonDistinctElements.add(s);

for(T nonDistinctElement : nonDistinctElements)
  if(list.indexOf(nonDistinctElement) != list.lastIndexOf(nonDistinctElement))
    list.remove(nonDistinctElement);
}

0

和使用commons-collections CollectionUtils.getCardinalityMap方法的版本:

final List<Integer> values = Arrays.asList(1, 1, 2, 3, 3, 3);
final Map<Integer, Integer> cardinalityMap = CollectionUtils.getCardinalityMap(values);
System.out.println(cardinalityMap
            .entrySet()
            .stream().filter(e -> e.getValue() > 1)
            .map(e -> e.getKey())
            .collect(Collectors.toList()));

```


0

这段代码怎么样-

public static void main(String[] args) {

    //Lets say we have a elements in array
    int[] a = {13,65,13,67,88,65,88,23,65,88,92};

    List<Integer> ls1 = new ArrayList<>();
    List<Integer> ls2 = new ArrayList<>();
    Set<Integer> ls3 = new TreeSet<>();

    //Adding each element of the array in the list      
    for(int i=0;i<a.length;i++) {
     {
    ls1.add(a[i]);
    }
    }

    //Iterating each element in the arrary
    for (Integer eachInt : ls1) {

    //If the list2 contains the iterating element, then add that into set<> (as this would be a duplicate element)
        if(ls2.contains(eachInt)) {
            ls3.add(eachInt);
        }
        else {ls2.add(eachInt);}

    }

    System.out.println("Elements in array or ls1"+ls1); 
    System.out.println("Duplicate Elements in Set ls3"+ls3);


}

0

以防万一,也希望同时包含重复项和非重复项。基本上,答案与正确答案相似,但不是从其他部分返回,而是返回其他部分

使用此代码(更改为所需的类型)

public Set<String> findDup(List<String> Duplicates){
    Set<String> returning = new HashSet<>();
    Set<String> nonreturning = new HashSet<>();
    Set<String> setup = new HashSet<>();
    for(String i:Duplicates){
        if(!setup.add( i )){
            returning.add( i );
        }else{
            nonreturning.add( i );
        }
    }
    Toast.makeText( context,"hello set"+returning+nonreturning+" size"+nonreturning.size(),Toast.LENGTH_SHORT ).show();
    return nonreturning;
}

0

更通用的方法作为https://stackoverflow.com/a/52296246的变体

    /**
     * Returns a duplicated values found in given collection based on fieldClassifier
     *
     * @param collection given collection of elements
     * @param fieldClassifier field classifier which specifies element to check for duplicates(useful in complex objects).
     * @param <T> Type of element in collection
     * @param <K> Element which will be returned from method in fieldClassifier.
     * @return returns list of values that are duplocated.
     */
    public static <T, K> List<K> lookForDuplicates(List<T> collection, Function<? super T, ? extends K> fieldClassifier) {

        return collection.stream().collect(Collectors.groupingBy(fieldClassifier))
                         .entrySet()
                         .stream()
                         .filter(e -> e.getValue().size() > 1)
                         .map(Map.Entry::getKey)
                         .collect(Collectors.toList());
    }

-1

如果您知道最大值(例如<10000),则可以牺牲速度空间。我不记得这项技术的确切名称。

伪代码:

//does not handle case when mem allocation fails 
//probably can be extended to unknown values /larger values .
maybe by sorting first
public List<int> GetDuplicates(int max)
{   
    //allocate and clear memory to 0/false
    bit[] buckets=new bit[max]
    memcpy(buckets,0,max);
    //find duplicates
    List<int> result=new List<int>();
    foreach(int val in List)
    {
        if (buckets[val])
        {
            result.add(value);
        }
        else
        {
            buckets[val]=1;
        }
    }
    return  result
}

我想您要的是“布尔值”而不是“位”?您在发布代码之前执行了代码吗?这是一个好的开始。如果您看一下HashSet(),那么您会看到它是您想要的“存储桶”实现。
johnstosh

-1

试试这个:

例如,如果列表值是:[1、2、3、4、5、6、4、3、7、8]重复项[3、4]。

Collections.sort(list);
        List<Integer> dup = new ArrayList<>();
        for (int i = 0; i < list.size() - 1; i++) {
            if (list.get(i) == list.get(i + 1)) {
                if (!dup.contains(list.get(i + 1))) {
                    dup.add(list.get(i + 1));
                }
            }
        }
        System.out.println("duplicate item " + dup);

在ArrayList()上调用contains()是一项昂贵的操作,因此应考虑改用Set。您将看到使用HashSet()或其链接版本的其他解决方案。
johnstosh
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.