整数リスト内の重複する要素をリストアップしようとしています。
List<Integer> numbers = Arrays.asList(new Integer[]{1,2,1,3,4,4});
jdk8のStreamsを使用します。誰かが試しましたか。重複を削除するには、distinct()APIを使用できます。しかし、重複した要素を見つけるのはどうですか?誰かが私を助けることができますか?
整数リスト内の重複する要素をリストアップしようとしています。
List<Integer> numbers = Arrays.asList(new Integer[]{1,2,1,3,4,4});
jdk8のStreamsを使用します。誰かが試しましたか。重複を削除するには、distinct()APIを使用できます。しかし、重複した要素を見つけるのはどうですか?誰かが私を助けることができますか?
回答:
あなたが使用することができますCollections.frequency
:
numbers.stream().filter(i -> Collections.frequency(numbers, i) >1)
.collect(Collectors.toSet()).forEach(System.out::println);
基本的な例。前半は頻度マップを作成し、後半はそれをフィルタリングされたリストに減らします。おそらくデイブの答えほど効率的ではありませんが、より用途が広いです(正確に2つを検出したい場合など)。
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() );
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]
filter()
ステートレス述語が必要です。あなたの「解決策」は、javadocで与えられたステートフル述語の例と非常に似ています:docs.oracle.com/javase/8/docs/api/java/util/stream/…–
sequential()
、おそらく安全です。ストリームが存在する可能性があるより一般的なケースではparallel()
、奇妙な方法で中断することがほぼ保証されています。
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());
このアプローチでは、スペースの複雑さが2倍になりますが、そのスペースは無駄ではありません。実際には、セットとしてのみ複製されたものと、すべての複製も削除された別のセットがあります。
マイStreamExのJavaの8ストリームを強化するライブラリは、特別な操作を提供しdistinct(atLeast)
、少なくとも指定された回数を表示される要素のみを保持することができます。したがって、問題は次のように解決できます。
List<Integer> repeatingNumbers = StreamEx.of(numbers).distinct(2).toList();
内部的には@Daveソリューションに似ており、オブジェクトをカウントして他の必要な量をサポートしConcurrentHashMap
、並列対応です(並列化されたストリームに使用しますがHashMap
、順次に使用します)。大量のデータの場合は、を使用して高速化できます.parallel().distinct(2)
。
あなたはこのように複製を得ることができます:
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());
numbers = Arrays.asList(400, 400, 500, 500);
stream
内部を持つことstream
はコストがかかります。
この質問に対する基本的な解決策は次のようになります。
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());
さて、フィルター操作を実行することはお勧めしませんが、理解を深めるために、私はそれを使用しました。さらに、将来のバージョンではいくつかのカスタムフィルターがあるはずです。
追加のマップまたはストリームの作成には、時間とスペースがかかります…
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() );
}
私はこのような問題を修正するための良い解決策があると思います-リスト=> 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(...)にあります:)
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'sが同じであることを確認せず、等しいと見なされるために、重複として削除される予定です。これは許容できるリスクである可能性があります。またはObjects.hash
、ドメイン全体で一意の結果を生成することが保証されている以外の関数を使用することもできます。
Java 8イディオム(スチーム)を使用する必要がありますか?Perphapsの簡単な解決策は、複雑さを、数値をキーとして(繰り返しなしで)保持し、それが値として発生する回数を保持するマップのようなデータ構造に移動することです。あなたは彼らがそのマップを繰り返すことができますが、それは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());
}
}
}
このソリューションを試してください:
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;
}
}
インデックスのチェックはどうですか?
numbers.stream()
.filter(integer -> numbers.indexOf(integer) != numbers.lastIndexOf(integer))
.collect(Collectors.toSet())
.forEach(System.out::println);