J'essaie de lister les éléments en double dans la liste d'entiers, par exemple,
List<Integer> numbers = Arrays.asList(new Integer[]{1,2,1,3,4,4});
using Streams of jdk 8. Quelqu'un at-il essayé. Pour supprimer les doublons, nous pouvons utiliser l'API distinct (). Mais qu'en est-il de trouver les éléments dupliqués? Quelqu'un peut-il m'aider?
java
lambda
java-8
java-stream
Siva
la source
la source
Réponses:
Vous pouvez utiliser
Collections.frequency
:numbers.stream().filter(i -> Collections.frequency(numbers, i) >1) .collect(Collectors.toSet()).forEach(System.out::println);
la source
Exemple de base. La première moitié construit la carte de fréquence, la seconde moitié la réduit à une liste filtrée. Probablement pas aussi efficace que la réponse de Dave, mais plus polyvalente (comme si vous voulez en détecter exactement deux, etc.)
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() );
la source
Vous avez besoin d'un ensemble (
allItems
ci-dessous) pour contenir tout le contenu du tableau, mais c'est 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]
la source
filter()
nécessite un prédicat sans état. Votre «solution» est étonnamment similaire à l'exemple d'un prédicat avec état donné dans le javadoc: docs.oracle.com/javase/8/docs/api/java/util/stream/…sequential()
, c'est probablement sûr. Dans le cas plus général où le flux peut êtreparallel()
, il est à peu près garanti qu'il se cassera de manière étrange.Une manière O (n) serait comme ci-dessous:
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());
La complexité de l'espace doublerait dans cette approche, mais cet espace n'est pas un gaspillage; en fait, nous avons maintenant le dupliqué seul uniquement en tant qu'ensemble ainsi qu'un autre ensemble avec tous les doublons supprimés également.
la source
Ma bibliothèque StreamEx qui améliore les flux Java 8 fournit une opération spéciale
distinct(atLeast)
qui ne peut conserver que les éléments apparaissant au moins le nombre de fois spécifié. Ainsi, votre problème peut être résolu comme ceci:List<Integer> repeatingNumbers = StreamEx.of(numbers).distinct(2).toList();
En interne, c'est similaire à la solution @Dave, il compte les objets, pour prendre en charge d'autres quantités voulues et il est compatible avec le parallèle (il utilise
ConcurrentHashMap
pour le flux parallélisé, maisHashMap
pour le séquentiel). Pour de grandes quantités de données, vous pouvez accélérer l'utilisation.parallel().distinct(2)
.la source
Vous pouvez obtenir le dupliqué comme ceci:
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());
la source
numbers = Arrays.asList(400, 400, 500, 500);
stream
intérieurstream
est coûteux.Je pense que les solutions de base à la question devraient être les suivantes:
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());
Eh bien, il n'est pas recommandé d'effectuer une opération de filtrage, mais pour une meilleure compréhension, je l'ai utilisé, de plus, il devrait y avoir une filtration personnalisée dans les versions futures.
la source
Un multiset est une structure qui maintient le nombre d'occurrences pour chaque élément. Utilisation de l'implémentation de Guava:
Set<Integer> duplicated = ImmutableMultiset.copyOf(numbers).entrySet().stream() .filter(entry -> entry.getCount() > 1) .map(Multiset.Entry::getElement) .collect(Collectors.toSet());
la source
la création d'une carte ou d'un flux supplémentaire prend du temps et de l'espace…
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]
… Et dont la question est prétendument un [duplicata]
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() ); }
la source
Si vous avez seulement besoin de détecter la présence de doublons (au lieu de les lister, ce que voulait l'OP), convertissez-les simplement en liste et ensemble, puis comparez les tailles:
List<Integer> list = ...; Set<Integer> set = new HashSet<>(list); if (list.size() != set.size()) { // duplicates detected }
J'aime cette approche car elle a moins de place pour les erreurs.
la source
Je pense avoir une bonne solution pour résoudre un problème comme celui-ci - Liste => Liste avec regroupement par Something.a & Something.b. Il existe une définition étendue:
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); } }
classe A, list1 ce ne sont que des données entrantes - la magie est dans Objects.hash (...) :)
la source
Objects.hash
produit la même valeur pour(v.a_1, v.b_1, v.c_1, v.d_1)
et(v.a_2, v.b_2, v.c_2, v.d_2)
, alors ils vont être considérés comme égaux et supprimés en tant que doublons, sans réellement vérifier que les a, b, c et d sont les mêmes. Cela peut être un risque acceptable, ou vous pouvez utiliser une fonction autre que celleObjects.hash
qui garantit un résultat unique sur votre domaine.Devez-vous utiliser les idiomes java 8 (steams)? Peut-être qu'une solution simple serait de déplacer la complexité vers une structure de données de carte qui contient les nombres comme clé (sans se répéter) et les heures auxquelles il se produit en tant que valeur. Vous pouvez les itérer sur cette carte et ne faire quelque chose qu'avec les nombres qui se produisent> 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()); } } }
la source
Essayez cette 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; } }
la source
Et la vérification des index?
la source