Java 8,使用Streams查找重复元素

118

我试图列出整数列表中重复的元素,例如:

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

使用JDK 8的Streams功能。有人尝试过吗?为了删除重复元素,我们可以使用distinct() API。但是如果想要查找重复的元素呢?有人能帮我吗?


如果您不想收集流,则本质上可以归结为“如何在流中同时查看多个项目”? - Thorbjørn Ravn Andersen
1
Set<Integer> items = new HashSet(); numbers.stream().filter(n -> !items.add(n)).collect(Collectors.toSet()); - Saroj Kumar Sahoo
18个回答

1
什么时候检查索引?
        numbers.stream()
            .filter(integer -> numbers.indexOf(integer) != numbers.lastIndexOf(integer))
            .collect(Collectors.toSet())
            .forEach(System.out::println);

1
应该可以正常工作,但是性能也像其他一些解决方案一样是O(n^2)。 - Florian Albrecht

1

如果你追求性能,使用Set.add()会更快。

public class FindDuplicatedBySet {

public static void main(String[] args) {
    List<Integer> list = Arrays.asList(5, 3, 4, 1, 3, 7, 2,3,1, 9, 9, 4,1);
    Set<Integer> result = findDuplicatedBySetAdd(list);
    result.forEach(System.out::println);
  }

public static <T> Set<T> findDuplicatedBySetAdd(List<T> list) {
    Set<T> items = new HashSet<>();
    return list.stream()
            .filter(n -> !items.add(n))
            .collect(Collectors.toSet());
  }
}

为什么这不是所有答案中最好和最简单的呢?一些基准测试显示它也是最快的。https://mkyong.com/java8/java-8-find-duplicate-elements-in-a-stream/ - supernova

0

你必须使用Java 8的惯用语(流)吗?也许一个简单的解决方案是将复杂性移动到类似于地图的数据结构中,该数据结构将数字作为键(不重复),并将其出现次数作为值。然后,您可以迭代该映射,并仅对出现次数大于1的那些数字执行某些操作。

import java.lang.Math;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;

public class RemoveDuplicates
{
  public static void main(String[] args)
  {
   List<Integer> numbers = Arrays.asList(new Integer[]{1,2,1,3,4,4});
   Map<Integer,Integer> countByNumber = new HashMap<Integer,Integer>();
   for(Integer n:numbers)
   {
     Integer count = countByNumber.get(n);
     if (count != null) {
       countByNumber.put(n,count + 1);
     } else {
       countByNumber.put(n,1);
     }
   }
   System.out.println(countByNumber);
   Iterator it = countByNumber.entrySet().iterator();
    while (it.hasNext()) {
        Map.Entry pair = (Map.Entry)it.next();
        System.out.println(pair.getKey() + " = " + pair.getValue());
    }
  }
}

0

尝试这个解决方案:

public class Anagramm {

public static boolean isAnagramLetters(String word, String anagramm) {
    if (anagramm.isEmpty()) {
        return false;
    }

    Map<Character, Integer> mapExistString = CharCountMap(word);
    Map<Character, Integer> mapCheckString = CharCountMap(anagramm);
    return enoughLetters(mapExistString, mapCheckString);
}

private static Map<Character, Integer> CharCountMap(String chars) {
    HashMap<Character, Integer> charCountMap = new HashMap<Character, Integer>();
    for (char c : chars.toCharArray()) {
        if (charCountMap.containsKey(c)) {
            charCountMap.put(c, charCountMap.get(c) + 1);
        } else {
            charCountMap.put(c, 1);
        }
    }
    return charCountMap;
}

static boolean enoughLetters(Map<Character, Integer> mapExistString, Map<Character,Integer> mapCheckString) {
    for( Entry<Character, Integer> e : mapCheckString.entrySet() ) {
        Character letter = e.getKey();
        Integer available = mapExistString.get(letter);
        if (available == null || e.getValue() > available) return false;
    }
    return true;
}

}

0
使用流(stream)
Set<Integer> set = new HashSet<>();
list.stream()
     .filter(data -> !set.add(data))
     .forEach(data -> System.out.println("duplicates "+data));

0

我认为我有一个很好的解决方案,可以解决像这样的问题 - List => 按Something.a和Something.b分组的List。 这里有一个扩展定义:

public class Test {

    public static void test() {

        class A {
            private int a;
            private int b;
            private float c;
            private float d;

            public A(int a, int b, float c, float d) {
                this.a = a;
                this.b = b;
                this.c = c;
                this.d = d;
            }
        }


        List<A> list1 = new ArrayList<A>();

        list1.addAll(Arrays.asList(new A(1, 2, 3, 4),
                new A(2, 3, 4, 5),
                new A(1, 2, 3, 4),
                new A(2, 3, 4, 5),
                new A(1, 2, 3, 4)));

        Map<Integer, A> map = list1.stream()
                .collect(HashMap::new, (m, v) -> m.put(
                        Objects.hash(v.a, v.b, v.c, v.d), v),
                        HashMap::putAll);

        list1.clear();
        list1.addAll(map.values());

        System.out.println(list1);
    }

}

类A,list1只是传入的数据 - 魔法在于Objects.hash(...) :)


1
警告:如果Objects.hash对于(v.a_1,v.b_1,v.c_1,v.d_1)(v.a_2,v.b_2,v.c_2,v.d_2)产生相同的值,则它们将被视为相等并作为重复项被删除,而不实际检查a,b,c和d是否相同。这可能是可以接受的风险,或者您可能希望使用除Objects.hash之外的其他函数,该函数保证在您的域中产生唯一结果。 - Marty Neal

0
**How to find Non-Repeated Numbers from the array using java8**

Integer[] intArr = {1,1,3,2,2,5,4,4,7,6,6,9,8,8,10,13};

Set<Integer> result = Arrays.asList(intArr).stream().
filter(x -> Collections.frequency(Arrays.asList(intArr), x) == 1).
        collect(Collectors.toSet());

 System.out.println(result); //output : [3, 5, 7, 9, 10, 13] **Non-duplicate** values


**How to find repeated Numbers from array using java8**

Set<Integer> set = new HashSet();

Set<Integer> result = Arrays.asList(intArr).stream().filter(x -> !set.add(x)).collect(Collectors.toSet());
    
System.out.println(result); // output : [1, 2, 4, 6, 8]  it returns **Duplicates values.**

1
第一部分并不是问题的答案,第二部分(基本上)是早期答案的副本 - 我错过了什么新闻?顺便说一句:请正确格式化您的答案(在代码中,缩进很重要,而不是在代码中应该..不被格式化为这样;) - kleopatra

-1

在流上使用distinct可以过滤重复项,您可以将其收集为set或List。

 numbers.stream().distinct().collect(Collectors.toSet())

问题是如何找到重复项,而不是删除它们。 - John Churchill

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接