Fournir un itérateur sur le contenu des deux listes en même temps?
Supposons que j'ai ceci:
public class Unit<MobileSuit, Pilot> {
...
List<MobileSuit> mobileSuits;
List<Pilot> pilots;
...
}
Et je voudrais parcourir la paire de chacun dans la façon la plus simple à l'extérieur de la classe. Comment dois-je faire? J'ai pensé à cela:
public class Unit<MobileSuit, Pilot> {
...
Iterator<MobileSuit> iteratinMechas;
Iterator<Pilot> iteratinPeople;
class IteratorCustom<MobileSuit, Pilot> implements Iterator {
public boolean hasNext() {
return iteratinMechas.hasNext() && iteratinPeople.hasNext();
}
public void remove() {
iteratinMechas.remove();
iteratinPeople.remove();
}
public Object next() {
///!\
}
}
public Iterator iterator() {
return new IteratorCustom<MobileSuit, Pilot>(mobileSuits, pilots);
}
}
Quelque chose le long de ces lignes.
De toute façon, le problème est que je ne peux pas vraiment revenir juste un seul objet à partir de next(), et j'ai aussi ne peut pas avoir un Itérateur prendre plus d'un type. Donc, toutes les pensées?
Aussi, je ne peux pas faire une nouvelle classe de combiner MobileSuit et Pilote. J'ai besoin de les garder séparés, même si je suis une itération à travers les deux à la fois. La raison en est qu'il peut être Mobile Costumes qui n'ont pas de pilotes, et je ne suis pas sûr de la façon de corriger cela en de les garder à la même classe. Cette classe a besoin d'être traitées dans d'autres endroits, donc, je n'aurais d'unifier une interface et un tas d'autres choses. Fondamentalement, supposons MobileSuit et le Pilote doivent être séparées.
- Si il va y avoir des mobilesuits qui n'ont pas de pilotes, je suis en supposant que vous avez de plus en plus mobiles convient que les pilotes. Que peut faire votre chèque pour hasNext() problématique, car il ne retourne true si il y a plus d'éléments dans les deux listes. Je pense que ça pourrait aider à obtenir la réponse à votre question, si vous pouvez fournir un peu plus d'infos sur les critères de comment vous pouvez combiner les deux.
- Cooney Ouais, maintenant que vous le dites, que hasNext() serait à tout le moins de mal.
- OMG +1 pour le Gundam-ish question.
- Question très intéressante. Je n'avais pas entendu parler de la fermeture à glissière avant stackoverflow.com/questions/1115563/... alors je me demandais "Pourquoi ne pas Goyave en charge?" Apparemment, il n'en interne. Il y a eu un débat sur la soutenir de l'extérieur - voir code.google.com/p/guava-libraries/issues/detail?id=35 Il y a une question connexe, ici stackoverflow.com/questions/5278040/...
- Pour parcourir en parallèle des collections en général, voir la Façon la plus élégante parcourir en parallèle des collections? bien qu'ici c'est différent parce que vous voulez effectuer une itération à l'extérieur de la classe.
- Notez que si votre
Unit
classe fournit uniterator()
méthode, en général, vous voulez ajouterimplements Iterable<...>
de la classe de signature.
Vous devez vous connecter pour publier un commentaire.
Évidemment, vous allez avoir besoin d'un peu de poids à la "paire" de la classe. C'est à peu près similaire à la
Map.Entry
intérieur de la classe.Voici un premier montage à une solution générique:
Remarque: ce n'est pas explicitement les cas où les listes sont de différentes longueurs. Ce qui va arriver, c'est que des éléments supplémentaires à la fin de la liste la plus longue seront ignorées silencieusement.
C'est copié+édité par Stephen C de la réponse. N'hésitez pas à utiliser:
Cela s'arrête dès que la liste est à partir d'éléments, de sorte que vous pourriez vouloir vérifier les listes de même taille qu'avant la création d'un IterablePair.
Qui ne semble pas correcte. Il semble que vous ne pouvez pas remplacer MobileSuit et Pilote par une seule classe, mais je ne vois aucune raison pourquoi vous ne pouvez pas avoir une seule classe qui combine eux - c'est à dire celui qui a juste un
getPilot()
méthode et ungetMobileSuit()
méthode. Vous pouvez utiliser un génériquePair
classe pour le même objectif, mais une classe personnalisée serait plus facile à utiliser.D'autre part, si vous voulez faire ce genre de "compression" de l'opération en plusieurs endroits, il pourrait être une solution. Alternativement, vous pouvez écrire une interface générique pour représenter la loi de combiner les deux articles distincts - qui pourrait revenir à un
SuitedPilot
ou quel que soit votre classe de combinaison est.Vous pouvez utiliser les valeurs null, droit? Qui est la façon correcte de le faire - demander à chaque fonction de garder la trace de ses pilotes. Si elle n'a pas de pilote, puis indiquer qu'avec une valeur null là.
Mais, si vous êtes ensemble mort sur de ne pas le faire pour une raison...
Pourquoi ne pas avoir une classe MannedMobileSuit comme une sous-classe de MobileSuit qui contient une instance d'un pilote ? Qui permettrait de résoudre votre problème en ayant un getPilot méthode.
Habituellement, lorsque vous obtenez ces problèmes (besoin de retourner deux cas), c'est que votre modèle d'Objet n'est pas appropriée et devrait être changé. Gardez vos options ouvertes
C'est très bien, mais ici vous essayez de les traiter comme une unité, de sorte que la structure de votre code de cette façon. Les suggestions ci-dessus à utiliser un
Pair
classe ouMap.Entry
, mais c'est beaucoup mieux de fournir une clairement nommées par l'objet qui représente uneMobileSuit
avec unPilot
, par exemple:Alors, plutôt que de construire une coutume
Iterator
/Iterable
, il suffit d'écrire une fonction d'assistance qui zips des deux listes. Par exemple:Maintenant, vous n'avez pas besoin de maintenir un complexe personnalisé
Iterator
mise en œuvre - il suffit de s'appuyer sur celui qui existe déjà!On peut aussi généraliser
assignPilots()
dans un générique utilitaire qui fonctionne pour tout deux entrées, comme suit:Qui vous devez ensuite appeler comme ceci:
Exemple de code utilise Goyave's
Preconditions
etImmutableList
- si vous n'utilisez pas la Goyave il est assez facile d'en ligne et swap pourArrayList
, mais il suffit d'utiliser la Goyave 🙂mobileSuits
liste est plus longue, vous aurez uneIndexOutOfBoundsException
et sipilots
est plus vous aurez silencieusement tomber quelquesPilot
objets.Vous pouvez simplement utiliser un
Map<MobileSuit, Pilot>
, où unnull
valeur mappée à uneMobileSuit
indique pas de pilote. LeIterator
pourrait juste être unIterator<Map.Entry<MobileSuit, Pilot>>
récupérées parmap.entrySet().iterator()
.Map
changer la sémantique légèrement (pas de doublons autorisés) mais en général c'est une bien meilleure idée.Suis tombé sur cette page en essayant de résoudre ce problème, et s'avère qu'il y a une bibliothèque qui est déjà résolu à l'aide de Java 8 cours d'eau (découvrez le Zip de la fonction).
Vous pouvez convertir une liste à un flux de données simplement en appelant
list.stream()
https://github.com/poetix/protonpack
L'amélioration de la réponse par
user2224844
, voici une version simple, qui est de ne pas essayer de courir à une exception:N'est-ce pas assez ?
MobileSuit
à l'index i et lePilot
à l'index i, et le but ici est de fournir unIterator
qui expose cette relation. Ce code au lieu associe à chaqueMobileSuit
avec tousPilot
.