Comment puis-je détecter (en renvoyant true/false) si un ArrayList contient plusieurs éléments identiques en Java?
Merci beaucoup, Terry
Edit Oublié de mentionner que je ne cherche pas à comparer les "Blocs" les uns avec les autres, mais leurs valeurs entières. Chaque "bloc" a un int et c’est ce qui les rend différents. Je trouve l'int d'un bloc particulier en appelant une méthode nommée "getNum" (par exemple, table1 [0] [2] .getNum ();
Le plus simple: dump toute la collection dans un ensemble (à l'aide du constructeur Set (Collection) ou de Set.addAll), puis vérifiez si l'ensemble a la même taille que ArrayList.
List<Integer> list = ...;
Set<Integer> set = new HashSet<Integer>(list);
if(set.size() < list.size()){
/* There are duplicates */
}
Mise à jour: Si je comprends bien votre question, vous avez un tableau 2d de Block, comme dans
Table de blocs [] [];
et vous voulez détecter si une ligne d'entre eux a des doublons?
Dans ce cas, je pourrais faire ce qui suit en supposant que Block implémente correctement "equals" et "hashCode":
for (Block[] row : table) {
Set set = new HashSet<Block>();
for (Block cell : row) {
set.add(cell);
}
if (set.size() < 6) { //has duplicate
}
}
Je ne suis pas sûr à 100% de cela pour la syntaxe, il pourrait donc être plus sûr de l'écrire en tant que
for (int i = 0; i < 6; i++) {
Set set = new HashSet<Block>();
for (int j = 0; j < 6; j++)
set.add(table[i][j]);
...
Set.add
renvoie un booléen false si l’élément ajouté est déjà dans le jeu. Vous pouvez même court-circuiter et éteindre toute annonce qui renvoie false
si vous voulez simplement savoir s’il existe des doublons.
Code amélioré, utilisant la valeur de retour de Set#add
au lieu de comparer la taille de la liste et celle définie.
public static <T> boolean hasDuplicate(Iterable<T> all) {
Set<T> set = new HashSet<T>();
// Set#add returns false if the set does not change, which
// indicates that a duplicate element has been added.
for (T each: all) if (!set.add(each)) return true;
return false;
}
Si vous cherchez à éviter les doublons, vous devriez simplement couper le processus intermédiaire de détection des doublons et utiliser un Set .
Code amélioré pour retourner les éléments en double
public static <T> List getDuplicate(Collection<T> list) {
final List<T> duplicatedObjects = new ArrayList<T>();
Set<T> set = new HashSet<T>() {
@Override
public boolean add(T e) {
if (contains(e)) {
duplicatedObjects.add(e);
}
return super.add(e);
}
};
for (T t : list) {
set.add(t);
}
return duplicatedObjects;
}
public static <T> boolean hasDuplicate(Collection<T> list) {
if (getDuplicate(list).isEmpty())
return false;
return true;
}
Si vos éléments sont en quelque sorte comparables (le fait que l'ordre ait une signification réelle est indifférent - il doit simplement être cohérent avec votre définition d'égalité), la solution de suppression de doublons la plus rapide va trier la liste (0 (n log ( n))) puis faire un seul passage et chercher répété éléments (c'est-à-dire des éléments égaux qui se succèdent) (c'est O (n)).
La complexité globale va être O (n log (n)), ce qui est à peu près identique à ce que vous obtiendriez avec un ensemble (n fois long (n)), mais avec une constante beaucoup plus petite. En effet, la constante dans sort/déduction résulte du coût de la comparaison des éléments, alors que le coût de l'ensemble est le plus susceptible de résulter d'un calcul de hachage, plus une (éventuellement plusieurs) comparaisons de hachage. Si vous utilisez une implémentation Set basée sur le hachage, c'est-à-dire, une arborescence va vous donner un O (n log² (n)), ce qui est encore pire.
Si je comprends bien, cependant, vous n'avez pas besoin de supprimer dupliquer, mais simplement de tester leur existence. Donc, vous devriez coder à la main un algorithme de tri par fusion ou par tas sur votre tableau, qui se ferme simplement en retournant true (c'est-à-dire "il y a un dup") si votre comparateur renvoie 0, sinon, complète le tri et traverse le test du tableau trié à des fins de répétition. . En effet, dans un tri par fusion ou par tas, une fois le tri terminé, vous aurez comparé chaque paire en double, à moins que les deux éléments ne se trouvent déjà dans leur position finale (ce qui est peu probable). Ainsi, un algorithme de tri modifié devrait apporter une amélioration considérable des performances (il faudrait que je le prouve, mais je suppose que cet algorithme devrait se trouver dans O(log(n)) sur des données uniformément aléatoires. )
J'avais besoin de faire une opération similaire pour un Stream
, mais je n'ai pas pu trouver un bon exemple. Voici ce que je suis venu avec.
public static <T> boolean areUnique(final Stream<T> stream) {
final Set<T> seen = new HashSet<>();
return stream.allMatch(seen::add);
}
Cela a l'avantage de court-circuiter lorsque les doublons sont trouvés tôt plutôt que de devoir traiter tout le flux et n'est pas plus compliqué que de simplement tout mettre dans un Set
et de vérifier la taille. Donc, ce cas serait grossièrement:
List<T> list = ...
boolean allDistinct = areUnique(list.stream());
Avec Java 8+), vous pouvez utiliser l'API Stream:
boolean areAllDistinct(List<Block> blocksList) {
return blocksList.stream().map(Block::getNum).distinct().count() == blockList.size();
}
En deux mots: 1) assurez-vous que tous les éléments sont comparables 2) triez le tableau 2) parcourez le tableau et trouvez les doublons
le meilleur moyen de gérer ce problème est d’utiliser un HashSet:
ArrayList<String> listGroupCode = new ArrayList<>();
listGroupCode.add("A");
listGroupCode.add("A");
listGroupCode.add("B");
listGroupCode.add("C");
HashSet<String> set = new HashSet<>(listGroupCode);
ArrayList<String> result = new ArrayList<>(set);
Il suffit d’imprimer résultat arraylist et de voir le résultat sans doublon :)
Si vous voulez le jeu de valeurs en double:
import Java.util.ArrayList;
import Java.util.HashSet;
import Java.util.List;
import Java.util.Set;
public class FindDuplicateInArrayList {
public static void main(String[] args) {
Set<String> uniqueSet = new HashSet<String>();
List<String> dupesList = new ArrayList<String>();
for (String a : args) {
if (uniqueSet.contains(a))
dupesList.add(a);
else
uniqueSet.add(a);
}
System.out.println(uniqueSet.size() + " distinct words: " + uniqueSet);
System.out.println(dupesList.size() + " dupesList words: " + dupesList);
}
}
Et pensez probablement aussi à couper les valeurs ou à utiliser des minuscules… selon votre cas.
Pour connaître les doublons dans une liste, utilisez le code suivant: Il vous donnera l’ensemble contenant les doublons.
public Set<?> findDuplicatesInList(List<?> beanList) {
System.out.println("findDuplicatesInList::"+beanList);
Set<Object> duplicateRowSet=null;
duplicateRowSet=new LinkedHashSet<Object>();
for(int i=0;i<beanList.size();i++){
Object superString=beanList.get(i);
System.out.println("findDuplicatesInList::superString::"+superString);
for(int j=0;j<beanList.size();j++){
if(i!=j){
Object subString=beanList.get(j);
System.out.println("findDuplicatesInList::subString::"+subString);
if(superString.equals(subString)){
duplicateRowSet.add(beanList.get(j));
}
}
}
}
System.out.println("findDuplicatesInList::duplicationSet::"+duplicateRowSet);
return duplicateRowSet;
}
/**
* Method to detect presence of duplicates in a generic list.
* Depends on the equals method of the concrete type. make sure to override it as required.
*/
public static <T> boolean hasDuplicates(List<T> list){
int count = list.size();
T t1,t2;
for(int i=0;i<count;i++){
t1 = list.get(i);
for(int j=i+1;j<count;j++){
t2 = list.get(j);
if(t2.equals(t1)){
return true;
}
}
}
return false;
}
Exemple de classe concrète ayant remplacé equals()
:
public class Reminder{
private long id;
private int hour;
private int minute;
public Reminder(long id, int hour, int minute){
this.id = id;
this.hour = hour;
this.minute = minute;
}
@Override
public boolean equals(Object other){
if(other == null) return false;
if(this.getClass() != other.getClass()) return false;
Reminder otherReminder = (Reminder) other;
if(this.hour != otherReminder.hour) return false;
if(this.minute != otherReminder.minute) return false;
return true;
}
}
Cette réponse est écrite en Kotlin, mais peut facilement être traduite en Java.
Si la taille de votre bibliographie se situe dans une petite plage fixe, c'est une excellente solution.
var duplicateDetected = false
if(arrList.size > 1){
for(i in 0 until arrList.size){
for(j in 0 until arrList.size){
if(i != j && arrList.get(i) == arrList.get(j)){
duplicateDetected = true
}
}
}
}
ArrayList<String> withDuplicates = new ArrayList<>();
withDuplicates.add("1");
withDuplicates.add("2");
withDuplicates.add("1");
withDuplicates.add("3");
HashSet<String> set = new HashSet<>(withDuplicates);
ArrayList<String> withoutDupicates = new ArrayList<>(set);
ArrayList<String> duplicates = new ArrayList<String>();
Iterator<String> dupIter = withDuplicates.iterator();
while(dupIter.hasNext())
{
String dupWord = dupIter.next();
if(withDuplicates.contains(dupWord))
{
duplicates.add(dupWord);
}else{
withoutDupicates.add(dupWord);
}
}
System.out.println(duplicates);
System.out.println(withoutDupicates);
String tempVal = null;
for (int i = 0; i < l.size(); i++) {
tempVal = l.get(i); //take the ith object out of list
while (l.contains(tempVal)) {
l.remove(tempVal); //remove all matching entries
}
l.add(tempVal); //at last add one entry
}
Remarque: cela aura un impact majeur sur les performances car les éléments sont supprimés du début de la liste. Pour remédier à cela, nous avons deux options. 1) itérer dans l'ordre inverse et supprimer les éléments. 2) Utilisez LinkedList au lieu de ArrayList. En raison des questions biaisées posées lors des entretiens pour supprimer les doublons de la liste sans utiliser aucune autre collection, voici l'exemple ci-dessus. Dans le monde réel cependant, si je dois y parvenir, je vais mettre les éléments de List to Set en toute simplicité!