9

例如,我的列表包含 {4, 6, 6, 7, 7, 8} 并且我想要最终结果 = {6, 6, 7, 7}

一种方法是遍历列表并消除唯一值(在本例中为 4、8)。

除了遍历 list 之外,还有其他有效的方法吗?我问这个问题是因为我正在工作的列表非常大?我的代码是

List<Long> duplicate = new ArrayList();
for (int i = 0; i < list.size(); i++) {
     Long item = (Long) list.get(i);
     if (!duplicate.contains(item)) {
          duplicate.add(item);
         }
     }
4

13 回答 13

10

到目前为止,有一些很好的答案,但另一种选择只是为了好玩。循环遍历列表,尝试将每个数字放入 Set 中,例如HashSet。如果 add 方法返回 false,则您知道该数字是重复的,应该进入重复列表。

编辑:这样的事情应该这样做

Set<Number> unique = new HashSet<>();
List<Number> duplicates = new ArrayList<>();
for( Number n : inputList ) {
    if( !unique.add( n ) ) {
        duplicates.add( n );
    }
}
于 2013-06-25T22:50:09.157 回答
6

除了遍历 list 之外,还有其他有效的方法吗?

你可以雇佣一个魔法精灵,让它为你做这件事。如果不循环遍历它,您将如何做到这一点?如果您不遍历列表,您甚至无法查看元素。这就像你想把一大堆数字加在一起而不看这些数字。对元素求和比搜索重复元素或搜索唯一元素要容易得多。一般来说,97% 的代码所做的事情是循环遍历列表和数据并处理和更新它。

所以,说,你必须循环。现在您可能想要选择最有效的方式。想到了一些方法:

  • 对所有数字进行排序,然后仅循环一次以查找重复项(因为它们将彼此相邻)。但是,请记住,排序算法也会循环遍历数据。
  • 对于列表中的每个元素,检查是否存在具有相同值的另一个元素。(这就是你的做法。这意味着你有两个相互内部contains的循环。(当然循环遍历列表。))
于 2013-06-25T22:57:29.967 回答
4
List<Number> inputList = Arrays.asList(4, 6, 6, 7, 7, 8);
List<Number> result = new ArrayList<Number>();
for(Number num : inputList) {
   if(Collections.frequency(inputList, num) > 1) {
       result.add(num);
   }
}

我不确定效率,但我发现代码易于阅读(这应该是首选。

编辑:更改Lists.newArrayList()new ArrayList<Number>();

于 2013-06-25T22:39:39.217 回答
4

我喜欢回答Java 8, Streams to find the duplicate elements。解决方案仅返回唯一的重复项。

 Integer[] numbers = new Integer[] { 1, 2, 1, 3, 4, 4 };
 Set<Integer> allItems = new HashSet<>();
 Set<Integer> duplicates = Arrays.stream(numbers)
    .filter(n -> !allItems.add(n)) //Set.add() returns false if the item was already in the set.
    .collect(Collectors.toSet());
 System.out.println(duplicates); // [1, 4]
于 2015-07-03T12:02:39.447 回答
1

有一个

Map<Integer, Integer> numberToOccurance = new HashMap<Integer, Integer>();

维护计数和数字,最后迭代键集并获取超过一个计数的值

于 2013-06-25T22:32:21.500 回答
0
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class FindDuplicate {

    public static void main(String[] args) {

        // Load all your ArrayList
        List<String> list = new ArrayList<String>();
        list.add("Jhon");
        list.add("Jency");
        list.add("Mike");
        list.add("Dmitri");
        list.add("Mike");

        // Set will not allow duplicates
        Set<String> checkDuplicates = new HashSet<String>();

        System.out.println("Actual list " + list);
        for (int i = 0; i < list.size(); i++) {
            String items = list.get(i);
            if (!checkDuplicates.add(items)) {
                // retain the item from set interface
                System.out.println("Duplicate in that list " + items);
            }
        }

    }
}
于 2014-11-22T18:00:50.387 回答
0

理想情况下,您首先List应该是Set不允许重复的。作为循环的替代方法,您可以转换并切换到Set或在中间使用它来消除重复项,如下所示:

List<Long> dupesList = Arrays.asList(4L, 6L, 6L, 7L, 7L, 8L);

Set<Long> noDupesSet = new HashSet<Long>(dupesList);
System.out.println(noDupesSet); // prints: [4, 6, 7, 8]

// To convert back to List
Long[] noDupesArr = noDupesSet.toArray(new Long[noDupesSet.size()]);
List<Long> noDupesList = Arrays.asList(noDupesArr);
System.out.println(noDupesList); // prints: [4, 6, 7, 8]
于 2013-06-26T00:22:06.560 回答
0

使用 Guava 和 Java 8,它既简单又快速:

Multiset<Integer> multiset = HashMultiset.create(list);
return list.stream()
    .filter(i -> multiset.count(i) > 1)
    .collect(Collectors.toList());

第一行使用一种哈希映射计算计数。剩下的就更明显了。

像这样的东西可以模拟多重集:

HashMap<Integer, Integer> multiset = new HashMap<>();
list.stream().forEach(i -> 
    multiset.compute(i, (ignored, old) -> old==null ? 1 : old+1)));
于 2017-08-24T21:47:30.303 回答
0

lambda 再次节省了时间:

List<Long> duplicates = duplicate.stream()
  .collect( Collectors.collectingAndThen( Collectors.groupingBy( Function.identity() ),
    map -> {
      map.values().removeIf( v -> v.size() < 2 );  // eliminate unique values (4, 8 in this case)
      return( map.values().stream().flatMap( List::stream ).collect( Collectors.toList() ) );
    } ) );  // [6, 6, 7, 7]


上述解决方案的速度优化版本:

List<Long> duplicates = duplicate.stream().collect( Collectors.collectingAndThen(
    Collectors.groupingBy( Function.identity(), Collectors.counting() ),
    map -> {
      map.values().removeIf( v -> v < 2 );  // eliminate unique values (4, 8 in this case)
      return( map.entrySet().stream().collect( Collector.of( ArrayList<Long>::new, (list, e) -> {
        for( long n = 0; n < e.getValue(); n++ )
          list.add( e.getKey() );
      }, (l1, l2) -> null ) ) );
    } ) );  // [6, 6, 7, 7]

的长值duplicate不会被保存但会被计算——当然是最快和最节省空间的变体

于 2019-07-21T09:50:37.357 回答
0

以下将与Eclipse Collections一起使用:

IntBag bag = IntLists.mutable.with(4, 6, 6, 7, 7, 8).toBag().selectDuplicates();

如果您想要装箱值而不是原始值,则以下内容将起作用:

Bag<Integer> bag = Lists.mutable.with(4, 6, 6, 7, 7, 8).toBag().selectDuplicates();

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

于 2019-10-26T03:47:53.403 回答
0

尝试这个:

受此答案的启发:https ://stackoverflow.com/a/41262509/11256849

for (String s : yourList){
     if (indexOfNth(yourList, s, 2) != -1){
         Log.d(TAG, s);
      }
   }

使用此方法:

public static <T> int indexOfNth(ArrayList list, T find, int nthOccurrence) {
        if (list == null || list.isEmpty()) return -1;
        int hitCount = 0;
        for (int index = 0; index < list.size(); index++) {
            if (list.get(index).equals(find)) {
                hitCount++;
            }
            if (hitCount == nthOccurrence) return index;
        }
        return -1;
    }
于 2021-01-09T21:14:39.497 回答
-1

这是我的解决方案版本:

import java.util.ArrayList;

public class Main {

public static void main(String[] args) {

    ArrayList<Integer> randomNumbers = new ArrayList<Integer>();
    ArrayList<Integer> expandingPlace = new ArrayList<Integer>();
    ArrayList<Integer> sequenceOfDuplicates = new ArrayList<Integer>();

    for (int i = 0; i < 100; i++) {
        randomNumbers.add((int) (Math.random() * 10));
        expandingPlace.add(randomNumbers.get(i));
    }

    System.out.println(randomNumbers); // Original list.

    for (int i = 0; i < randomNumbers.size(); i++) {
        if (expandingPlace.get(i) == expandingPlace.get(i + 1)) {
            expandingPlace.add(0);
            sequenceOfDuplicates.add(expandingPlace.get(i)); 
            sequenceOfDuplicates.add(expandingPlace.get(i + 1));
        }
    }

    System.out.println(sequenceOfDuplicates); // What was in duplicate there.

}

}

它将从 0 到 9 的数字添加到列表中,并将“重复”中的内容(数字后跟相同的数字)添加到另一个列表中。你可以使用你的大列表代替我的 randomNumbers ArrayList。

于 2013-06-25T23:04:57.620 回答
-1

鉴于您可以通过仅循环一次列表来做到这一点,我不会太担心性能。如果您寻找更高性能的解决方案,那么您最终可能会使代码过于复杂,并且可读性和可维护性会受到影响。归根结底,如果您想检查整个列表是否有重复项,那么您必须访问每个元素。

我建议编写明显的解决方案,看看它是如何执行的。您可能会惊讶于 Java 迭代列表的速度有多快,即使它特别大。

于 2013-06-25T22:34:45.117 回答