Cette fonction ne doit renvoyer true que si l'objet paramètre est un sous-ensemble de l'objet appelant mais elle renvoie toujours true. Comment y remédier?
public boolean contains(FileCollection other) { int i = 0; int j = 0; for (i = 0; i<other.files.length; i++) { for (j = 0; j<this.files.length; j++) { if ((other.files[i]).equals((this.files[j]))) //this refers to the equals method defined in File class break; } if (j==this.files.length) return false; } return true;//this method is in FileCollection class }
5 Réponses :
(Puisque vous n'avez pas explicitement exprimé le type de données des éléments du tableau, je suppose que c'est File
, déduit des commentaires.)
Si cela ne vous dérange pas de convertir entre les structures de données, peut-être convertir vos tableaux (temporairement) en collections est le moyen le plus simple. Par exemple, conversion en List
:
public boolean contains(FileCollection other) { Map<File,Integer> otherFrequency = Arrays.stream(other.files) .collect(Collectors.toMap(Function.identity(), v->1,Integer::sum)); Map<File,Integer> thisFrequency = Arrays.stream(this.files) .collect(Collectors.toMap(Function.identity(), v->1,Integer::sum)); if (thisFrequency.entrySet().containsAll(otherFrequency).entrySet()) { for (File entry : otherFrequency.entrySet()) { if (thisFrequency.get(entry) < otherFrequency.get(entry)) return false; } return true; } return false; }
En fonction de votre clarification de ce qui doit être considéré comme "contient" lorsque les éléments dupliqués sont autorisés, je ' Je dis que vous devez compter le nombre d'existence pour chaque élément. Voici comment:
Sur la base de la réponse de @Eritrean, vous pouvez obtenir et stocker le décompte sur une carte. J'ai également apporté des modifications pour vérifier le décompte:
/* @param other * @return true if the calling object contains * all files in the parameter object, false otherwise */ public boolean contains(FileCollection other) { List<File> myList = Arrays.asList(this.files); List<File> otherList = Arrays.asList(other.files); return myList.containsAll(otherList); }
J'écrivais exactement la même suggestion :-)
Remplacez List
par List
il retourne toujours faux
@BhushanOza Y a-t-il donc des éléments dupliqués dans chaque tableau?
@renyuneyun oui il peut avoir des éléments en double
@RobertKock Mais nous ne connaîtrons pas le type exact, uniquement indiqué dans le commentaire; p
@BhushanOza Et comment définir "contient" quand this.files
a un A
tandis que other.files
a deux A code> s? Est-ce
vrai
ou faux
en fonction de vos besoins?
@renyuneyun Les fichiers ont de nombreux attributs comme le nom, la taille, etc. qui doivent être égaux pour que le tableau File soit un sous-ensemble. C'est pourquoi j'ai utilisé ma méthode File.equals () dans la question
@BhushanOza Oui, j'en suis conscient, et les méthodes containsAll ()
utilisent equals ()
en interne. Mais le problème n'est pas là. Le problème est de savoir ce que vous définissez comme "contient", lorsque this.files
a un élément A
tandis que other.files code> a deux exactement les mêmes
A
s (de la préoccupation de equals ()
)? Cela devrait-il être true
ou false
de votre point de vue?
@renyuneyun qui devrait être faux
@renyuneyun Vous avez raison. J'ai à nouveau modifié la réponse.
@BhushanOza Puisqu'il n'y a toujours pas de réponses ciblant le scénario dupliqué, j'ai ajouté cela à ma réponse. J'espère que ceci résoudra votre problème. Vous aurez besoin du nombre stocké dans une carte, sauf si vous avez trié la liste à l'avance (pour laquelle vous pouvez utiliser rightest_index_of_this_element - leftest_index_of_this_element
comme nombre).
@renyuneyun le code Map me donne 2 erreurs: 1. aucune méthode appropriée trouvée pour containsAll (Map
2. FileCollection.java:16: erreur: incompatible types: l'entrée
^
@renyuneyun J'ai corrigé la première erreur - les crochets étaient mal alignés
@renyuneyun La 2ème erreur a été corrigée en changeant Fichier en Entrée
Outre la suggestion @renyuneyun de convertir vos tableaux en listes, vous pouvez également utiliser la méthode String
contains
public boolean contains(FileCollection other) { String myList = Arrays.toString(this.files); String otherList = Arrays.toString(other.files); return myList.contains(otherList); }
Bien sûr, ces deux suggestions ne sont pas les solutions optimales du point de vue de la complexité, mais sont certainement les plus courtes :)
Pour que Ne connaissant pas la classe des Ou même Il existe des structures de données plus agréables qui accélèrent les choses et ont des méthodes prédéfinies pour des choses comme Avec des doublons En triant les deux tableaux, vous pouvez synchroniser la comparaison à des emplacements dans les deux tableaux. Ce qui précède gère les doublons. other.files
contienne this.files
à contenir, chaque this.file
doit être dans other.files code>.
Comparator<File> comparator = new Comparator<File>() {
@Override
public int compare(File lhs, File rhs) {
int cmp = lhs.getBase().compareIgnoreCase(rhs.getBase());
if (cmp == 0) {
cmp = lhs.getExtension().compareIgnoreCase(rhs.getExtension());
}
if (cmp == 0) {
cmp = Long.compare(lhs.getSize(), rhs.getSize());
}
return cmp;
}
};
Arrays.sort(this.files, comparator);
Arrays.sort(other.files, comparator);
int otherI = 0;
for (File file : this.files.length) {
boolean found = false;
while (otherI < other.files.length) {
int comparison = comparator.compare(other.files[otherI], file);
++otherI;
if (comparison >= 0) {
found = comparison == 0;
break;
}
}
if (!found) {
return false;
}
}
return true;
fichiers
, vous pouvez probablement faire: for (String file : this.files) {
boolean found = other.files.indexOf(file) != -1;
if (!found) {
return false;
}
}
return true;
for (String file : this.files) {
boolean found = false;
for (String otherFile : other.files) {
if (otherFile.equals(file)) {
found = true;
break;
}
}
if (!found) {
return false;
}
}
return true;
contains
.
for (int j = 0; j < this.files.length; j++) {
boolean found = false;
for (int i = 0; i < other.files.length; i++) {
if (other.files[i].equals(this.files[j])) {
found = true;
break;
}
}
if (!found) {
return false;
}
}
return true;
En utilisant votre première réponse, l'un des tests échoue - lorsque les deux tableaux ont chacun un double. Ça devrait être vrai mais ça se révèle faux
Dans ce cas, le tri a du sens, puis compter et vérifier les doublons est plus facile. Arrays.sort
.
Arrays.sort () ne fonctionne pas. La classe File a de nombreux attributs comme le nom, la taille, etc. Elle donne à ClassCastException
le Arrays.sort () lève ClassCastException
J'ai vu votre commentaire trop tard; a ajouté un comparateur. Pas sûr du fichier de classe, ni du champ à comparer.
La classe File a une méthode equals (). Cela peut être utilisé pour comparer
Malheureusement, il faut également un ordre de tri, <
. N'existe-t-il pas un moyen d'avoir le chemin complet sous forme de chaîne ou le nodeid sur Linux?
On pourrait comparer sur tous les attributs, le nom, quand 0, sur la taille, quand 0 sur .... Si vous avez la source de est égal à
, vous pouvez voir ce qui rend deux fichiers égaux.
Voici le code de la méthode equals: return (this.getBase (). EqualsIgnoreCase (other.getBase ()) && this.getExtension (). EqualsIgnoreCase (other.getExtension ()) && this.getSize () == autre .getSize () && this.getPermissions () == other.getPermissions ())
Vous pouvez activer cela dans une comparaison imbriquée {-1, 0, 1} en utilisant également getBase (). CompareIgnoreCase (...)
. Tant que la comparaison reste à 0, continuez avec l'attribut suivant.
pouvez-vous modifier votre réponse pour l’inclure? comme je ne sais pas comment faire ça
la ligne de comparaison donne cette erreur: '<>' ne peut pas être utilisé avec des classes anonymes
Changé en
. Dans le plus récent java, ce ne serait plus une erreur que j'ai supposée.
merci pour l'aide, mais cela échoue toujours à ce test
Merci pour la patience quand même.
Qu'en est-il de l'utilisation d'une carte avec Fichier comme clé et fréquence comme valeur:
public boolean contains(FileCollection other) { Map<File,Integer> otherFrequency = Arrays.stream(other.files) .collect(Collectors.toMap(Function.identity(), v->1,Integer::sum)); Map<File,Integer> thisFrequency = Arrays.stream(this.files) .collect(Collectors.toMap(Function.identity(), v->1,Integer::sum)); return thisFrequency.entrySet().containsAll(otherFrequency.entrySet()); }
Seule cette réponse fonctionne pour moi: (Crédit à @Joop Eggen pour la partie Comparateur)
public boolean contains(FileCollection other) { Comparator<File> comparator = new Comparator<File>() { @Override public int compare(File lhs, File rhs) { int cmp = lhs.getBase().compareToIgnoreCase(rhs.getBase()); if (cmp == 0) { cmp = lhs.getExtension().compareToIgnoreCase(rhs.getExtension()); } if (cmp == 0) { cmp = Long.compare(lhs.getSize(), rhs.getSize()); } if (cmp == 0) { cmp = Long.compare(lhs.getPermissions(), rhs.getPermissions()); } return cmp; } }; Arrays.sort(this.files, comparator); Arrays.sort(other.files, comparator); //THIS AND THE COMPARATOR SORT THE ARRAYS BASED ON ALL FILE ATTRIBUTES int i = 0; int j = 0; if (this.files.length<other.files.length) return false; while (i<other.files.length && j<this.files.length) { if (!(this.files[j].equals(other.files[i]))) j++; else { j++; i++; } } if (i<other.files.length) return false; else return true; }
@vincrichaud c'est très clair - j'ai dit que ça retournait toujours vrai. Mais la réponse ne doit être vraie que si l'objet paramètre est un sous-ensemble de l'objet appelant
Maintenant c'est, merci pour la modification
Votre boucle interne se termine lorsque
j = this.files.length + 1
@vincrichaud alors que devrait-il être?
La boucle se termine lorsque la condition ne correspond plus: lorsque
j = this.files.length +1
.Dans votre code, vous considérez qu'elle se termine lorsquej = this.files.length code>. Pour que votre code fonctionne correctement, il vous suffit de changer la condition if en la même que la condition for