Java 8, Streams에서 중복 요소 찾기
정수 목록에 중복 요소를 나열하려고합니다. 예를 들어,
List<Integer> numbers = Arrays.asList(new Integer[]{1,2,1,3,4,4});
jdk 8의 스트림을 사용하고 있습니다. 중복을 제거하기 위해 distinct () API를 사용할 수 있습니다. 하지만 중복 된 요소를 찾는 것은 어떻습니까? 아무도 나를 도울 수 있습니까?
다음을 사용할 수 있습니다 Collections.frequency
.
numbers.stream().filter(i -> Collections.frequency(numbers, i) >1)
.collect(Collectors.toSet()).forEach(System.out::println);
allItems
전체 배열 내용을 보관하려면 세트 ( 아래) 가 필요 하지만 이것은 O (n)입니다.
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]
기본 예. 전반부는 주파수 맵을 만들고 후반부는 필터링 된 목록으로 줄입니다. 아마도 Dave의 대답만큼 효율적이지는 않지만 더 다양합니다 (정확히 두 개를 감지하려는 경우 등).
List<Integer> duplicates = IntStream.of( 1, 2, 3, 2, 1, 2, 3, 4, 2, 2, 2 )
.boxed()
.collect( Collectors.groupingBy( Function.identity(), Collectors.counting() ) )
.entrySet()
.stream()
.filter( p -> p.getValue() > 1 )
.map( Map.Entry::getKey )
.collect( Collectors.toList() );
Java 8 스트림을 향상시키는 My StreamEx 라이브러리 distinct(atLeast)
는 지정된 횟수 이상 나타나는 요소 만 유지할 수 있는 특수 작업 을 제공합니다 . 따라서 다음과 같이 문제를 해결할 수 있습니다.
List<Integer> repeatingNumbers = StreamEx.of(numbers).distinct(2).toList();
내부적으로는 @Dave 솔루션과 유사하며, 원하는 수량을 지원하기 위해 객체를 계산하고 병렬 친화적입니다 ( ConcurrentHashMap
병렬 스트림에 사용되지만 HashMap
순차에 사용됨). 많은 양의 데이터의 경우를 사용하여 속도를 높일 수 있습니다 .parallel().distinct(2)
.
O (n) 방법은 다음과 같습니다.
List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 4, 4);
Set<Integer> duplicatedNumbersRemovedSet = new HashSet<>();
Set<Integer> duplicatedNumbersSet = numbers.stream().filter(n -> !duplicatedNumbersRemovedSet.add(n)).collect(Collectors.toSet());
이 접근 방식에서는 공간 복잡성이 두 배가 될 것이지만 그 공간은 낭비가 아닙니다. 사실, 우리는 이제 모든 복제물도 제거 된 다른 세트뿐만 아니라 세트로만 복제 된 것을 가지고 있습니다.
다음과 같이 복제 할 수 있습니다.
List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 4, 4);
Set<Integer> duplicated = numbers.stream().filter(n -> numbers.stream().filter(x -> x == n).count() > 1).collect(Collectors.toSet());
질문에 대한 기본적인 해결책은 다음과 같습니다.
Supplier supplier=HashSet::new;
HashSet has=ls.stream().collect(Collectors.toCollection(supplier));
List lst = (List) ls.stream().filter(e->Collections.frequency(ls,e)>1).distinct().collect(Collectors.toList());
글쎄, 필터 작업을 수행하는 것은 권장되지 않지만 더 나은 이해를 위해 사용했으며 향후 버전에는 사용자 지정 필터링이 있어야합니다.
다중 집합은 각 요소의 발생 수를 유지하는 구조입니다. Guava 구현 사용 :
Set<Integer> duplicated =
ImmutableMultiset.copyOf(numbers).entrySet().stream()
.filter(entry -> entry.getCount() > 1)
.map(Multiset.Entry::getElement)
.collect(Collectors.toSet());
추가지도 또는 스트림을 만드는 것은 시간과 공간이 많이 소요됩니다.
Set<Integer> duplicates = numbers.stream().collect( Collectors.collectingAndThen(
Collectors.groupingBy( Function.identity(), Collectors.counting() ),
map -> {
map.values().removeIf( cnt -> cnt < 2 );
return( map.keySet() );
} ) ); // [1, 4]
… 그리고 그 질문에 대해 [중복]
public static int[] getDuplicatesStreamsToArray( int[] input ) {
return( IntStream.of( input ).boxed().collect( Collectors.collectingAndThen(
Collectors.groupingBy( Function.identity(), Collectors.counting() ),
map -> {
map.values().removeIf( cnt -> cnt < 2 );
return( map.keySet() );
} ) ).stream().mapToInt( i -> i ).toArray() );
}
나는이 같은 문제를 해결하는 방법이 있다고 생각합니다-List => Something.a & Something.b로 그룹화 된 목록. 확장 된 정의가 있습니다.
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 (...)에 있습니다 :)
Do you have to use the java 8 idioms (steams)? Perphaps a simple solution would be to move the complexity to a map alike data structure that holds numbers as key (without repeating) and the times it ocurrs as a value. You could them iterate that map an only do something with those numbers that are ocurrs > 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());
}
}
}
Try this solution:
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;
}
}
What about checking of indexes?
numbers.stream()
.filter(integer -> numbers.indexOf(integer) != numbers.lastIndexOf(integer))
.collect(Collectors.toSet())
.forEach(System.out::println);
If you only need to detect the presence of duplicates (instead of listing them, which is what the OP wanted), just convert them into both a List and Set, then compare the sizes:
List<Integer> list = ...;
Set<Integer> set = new HashSet<>(list);
if (list.size() != set.size()) {
// duplicates detected
}
I like this approach because it has less places for mistakes.
참고URL : https://stackoverflow.com/questions/27677256/java-8-streams-to-find-the-duplicate-elements
'programing' 카테고리의 다른 글
숫자 'n'으로 나눌 수있는 바이너리 문자열을 허용하는 DFA 설계 (0) | 2020.11.06 |
---|---|
Gradle을 사용하여 jar에 리소스, 구성 파일 추가 (0) | 2020.11.06 |
Chrome 48 이상에서 웹 보안 비활성화 (0) | 2020.11.06 |
“완전한 바이너리 트리”,“엄격한 바이너리 트리”,“전체 바이너리 트리”의 차이점은 무엇입니까? (0) | 2020.11.06 |
IntelliJ IDEA에서 라이브러리 (android-support-v7-appcompat)를 어떻게 추가합니까? (0) | 2020.11.06 |