Ich versuche, doppelte Elemente in der Ganzzahlliste aufzulisten, z.
List<Integer> numbers = Arrays.asList(new Integer[]{1,2,1,3,4,4});
Verwenden von Streams von JDK 8. Hat jemand ausprobiert. Um die Duplikate zu entfernen, können wir die eindeutige () API verwenden. Aber was ist mit dem Finden der duplizierten Elemente? Kann mir jemand helfen?
java
lambda
java-8
java-stream
Siva
quelle
quelle
Antworten:
Sie können verwenden
Collections.frequency
:numbers.stream().filter(i -> Collections.frequency(numbers, i) >1) .collect(Collectors.toSet()).forEach(System.out::println);
quelle
Grundlegendes Beispiel. In der ersten Hälfte wird die Frequenzkarte erstellt, in der zweiten Hälfte wird sie auf eine gefilterte Liste reduziert. Wahrscheinlich nicht so effizient wie Daves Antwort, aber vielseitiger (wenn Sie genau zwei erkennen möchten usw.)
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() );
quelle
Sie benötigen einen Satz (
allItems
unten), um den gesamten Array-Inhalt aufzunehmen, aber dies ist 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]
quelle
filter()
erfordert ein zustandsloses Prädikat. Ihre "Lösung" ähnelt auffallend dem Beispiel eines Stateful-Prädikats im Javadoc: docs.oracle.com/javase/8/docs/api/java/util/stream/…sequential()
, ist er wahrscheinlich sicher. In dem allgemeineren Fall, in dem sich der Stream befindetparallel()
, ist es ziemlich garantiert, dass er auf seltsame Weise bricht.Ein O (n) Weg wäre wie folgt:
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());
Die Raumkomplexität würde sich bei diesem Ansatz verdoppeln, aber dieser Raum ist keine Verschwendung; Tatsächlich haben wir das Duplikat jetzt nur noch als Set sowie als weiteres Set, wobei auch alle Duplikate entfernt wurden.
quelle
Meine StreamEx- Bibliothek, die die Java 8-Streams erweitert, bietet eine spezielle Operation, bei
distinct(atLeast)
der nur Elemente beibehalten werden können, die mindestens so oft angezeigt werden . So kann Ihr Problem folgendermaßen gelöst werden:List<Integer> repeatingNumbers = StreamEx.of(numbers).distinct(2).toList();
Intern ähnelt es der @ Dave-Lösung, zählt Objekte, unterstützt andere gewünschte Mengen und ist parallel-freundlich (wird
ConcurrentHashMap
für parallelisierte Streams verwendet, jedochHashMap
für sequentielle Streams ). Für große Datenmengen können Sie eine Beschleunigung verwenden.parallel().distinct(2)
.quelle
Sie können das Duplikat wie folgt erhalten:
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());
quelle
numbers = Arrays.asList(400, 400, 500, 500);
stream
drinnen zu seinstream
.Ich denke, grundlegende Lösungen für die Frage sollten wie folgt sein:
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());
Nun, es wird nicht empfohlen, eine Filteroperation durchzuführen, aber zum besseren Verständnis habe ich sie verwendet. Außerdem sollte es in zukünftigen Versionen eine benutzerdefinierte Filterung geben.
quelle
Ein Multiset ist eine Struktur, die die Anzahl der Vorkommen für jedes Element beibehält. Verwenden der Guava-Implementierung:
Set<Integer> duplicated = ImmutableMultiset.copyOf(numbers).entrySet().stream() .filter(entry -> entry.getCount() > 1) .map(Multiset.Entry::getElement) .collect(Collectors.toSet());
quelle
Das Erstellen einer zusätzlichen Karte oder eines zusätzlichen Streams ist zeit- und platzaufwendig.
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]
… Und für die Frage, von der behauptet wird, sie sei ein [Duplikat]
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() ); }
quelle
Wenn Sie nur das Vorhandensein von Duplikaten erkennen müssen (anstatt sie aufzulisten, was das OP wollte), konvertieren Sie sie einfach in eine Liste und einen Satz und vergleichen Sie dann die Größen:
List<Integer> list = ...; Set<Integer> set = new HashSet<>(list); if (list.size() != set.size()) { // duplicates detected }
Ich mag diesen Ansatz, weil er weniger Orte für Fehler hat.
quelle
Ich denke, ich habe eine gute Lösung, um ein Problem wie dieses zu beheben - Liste => Liste mit Gruppierung nach Something.a & Something.b. Es gibt eine erweiterte Definition:
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); } }
Klasse A, Liste1, es sind nur eingehende Daten - Magie ist in den Objects.hash (...) :)
quelle
Objects.hash
derselbe Wert für(v.a_1, v.b_1, v.c_1, v.d_1)
und erzeugt wird(v.a_2, v.b_2, v.c_2, v.d_2)
, werden sie als gleich betrachtet und als Duplikate entfernt, ohne tatsächlich zu überprüfen, ob a, b, c und d gleich sind. Dies kann ein akzeptables Risiko sein, oder Sie möchten möglicherweise eine andere Funktion verwenden,Objects.hash
die garantiert ein eindeutiges Ergebnis für Ihre Domain liefert.Müssen Sie die Java 8-Redewendungen (Dämpfe) verwenden? Perphaps Eine einfache Lösung wäre, die Komplexität auf eine kartenähnliche Datenstruktur zu verlagern, die Zahlen als Schlüssel enthält (ohne sich zu wiederholen) und die Zeiten, zu denen sie als Wert auftreten. Sie könnten diese Karte iterieren und nur mit den Zahlen> 1 etwas tun.
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()); } } }
quelle
Versuchen Sie diese Lösung:
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; } }
quelle
Was ist mit der Überprüfung von Indizes?
quelle