2010-06-23 10 views
14

Je suis nouveau sur Java et j'ai besoin de faire une liste de listes de listes. Je pourrais le faire en python parce qu'un élément d'une liste peut être une liste donc dans une liste incorporée, list[0] se référerait à une liste et list[0][0] ferait référence à l'élément zeroeth de la liste incorporée. Existe-t-il un moyen facile d'implémenter ce comportement dans Java?Liste des listes de listes

Répondre

26

Toutes les autres réponses sont techniquement correctes, mais à mon humble avis si vous implémentez une liste approximative des listes de listes que vous ne traitent pas vos données au bon niveau d'abstraction. Par exemple, je suis à peu près sûr qu'une liste de listes signifie déjà "quelque chose" dans votre domaine d'activité. Encapsuler ce "quelque chose" dans un autre objet de sorte que vous pouvez simplement avoir une liste < Quelque chose > au lieu d'un difficile à utiliser et à maintenir Liste < Liste < Liste <Objet> >.

+2

Dans certaines langues (il est vrai que ce n'est pas typiquement Java, en raison de sa syntaxe verbeuse), l'utilisation d'une liste-de-liste-de-liste est assez courante pour le prototypage. Pour la programmation exploratoire, il peut être beaucoup plus facile de faire des changements lorsque vous n'avez pas de noms explicites intégrés partout. Une fois que vous écrivez une application web d'entreprise, bien sûr, vous avez besoin de «bon niveau d'abstraction» et de «votre domaine d'activité», mais si vous écrivez un programme à faire, je ne sais pas encore va ", les listes sont super. Le noyau Linux n'a pas démarré parfaitement factorisé, ni même en tant que noyau OS. – Ken

+8

J'ai entendu cette justification des milliers de fois dans ma vie professionnelle: "Je vais commencer par une liste de listes, je verrai ce qui se passera et ensuite je le retravaillerai." C'est un vœu pieux dans le cas du bast ou plus probablement juste un mensonge et le résultat final est que l'horrible liste de listes restera pour toujours dans votre code. Si vous savez déjà qu'il y a une meilleure façon d'écrire votre code (et il semble que vous êtes d'accord que vous pouvez faire quelque chose de mieux), pourquoi ne pas commencer de la meilleure façon possible? –

+0

Vous passerez quelques minutes à encapsuler ... faites-le et soyez élégant! –

12

Comme le dit Mario, vous devrez probablement faire abstraction de vos données un peu plus loin. Mais, ce qui suit fera ce dont vous avez besoin.

En Java vous donc quelque chose comme:

List<List<List<Object>>> listOfListsOfLists =new ArrayList<List<List<Object>>>(); 

Ensuite, pour accéder aux articles, vous utilisez:

listOfListsOfLists.get(a).get(b).get(c); 

Ou, pour itérer sur tout:

for (List<List<Object>> list2: listOfListsOfLists) { 
    for (List<Object> list1: list2) { 
     for (Object o: list1) { 
      // use `o` 
     } 
    } 
} 
5

Puisque toutes ces réponses me font barf, puis-je simplement ajouter la suggestion que vous pouvez soit

  1. Créer un type de données pour exprimer vos données tout en encapsulant les détails de la structure, ou au moins

  2. Créer un type de clé qui enveloppe un int [] (mais overrides égaux et hashCode correctement) et de l'utilisation un HashMap à la place? Il est généralement rare que toute votre structure tridimensionnelle soit remplie de toute façon.

Encore mieux, vous pouvez encapsuler cette carte et utiliser varargs pour un accès propre.

public class NDimensionalArray<V> { 
    private final int dimensions; 
    private final Map<Key, V> values = new HashMap<Key, V>(); 

    private NDimensionalArray(int dimensions) { 
     this.dimensions = dimensions; 
    } 

    public V get(int... indices) { 
     checkIndices(indices); 
     return values.get(new Key(indices)); 
    } 

    public void set(V value, int... indices) { 
     checkIndices(indices); 
     values.put(new Key(indices), value); 
    } 

    private void checkIndices(int[] indices) { 
     if (indices.length != dimensions) { 
      throw new IllegalArgumentException(); 
     } 
    } 

    private static final class Key { 
     private final int[] indices; 

     private Key(int[] indices) { 
      this.indices = indices; 
     } 

     @Override 
     public int hashCode() { 
      return Arrays.hashCode(indices); 
     } 

     @Override 
     public boolean equals(Object obj) { 
      return Arrays.equals(indices, ((Key)obj).indices); 
     } 
    } 
} 

Si les gens ont des exemples de collections établies bibliothèques qui font déjà ce genre de chose, laissez-moi savoir et je vais ajouter des liens.

+0

Moi aussi, j'ai eu un peu de mal à voir certains exemples de code. –

+0

Soit il me manque quelque chose, ou il y a un défaut ici - les hashcodes de tableau sont basés sur l'identité, pas sur les valeurs dans le tableau - vos clefs de carte ne fonctionneront pas comme prévu? Une classe de détenteurs de données qui définit un hashCode basé sur les valeurs fonctionnerait si les plages de valeurs permettaient un hashCode sans collision (ie index 0 .. 1000 et hashCode = 1000000 * a [2] + 1000 * a [1] + a [ 0]) – rsp

+0

@rsp: Merci, vous avez absolument raison. Était un peu trop hâtivement jeté ensemble. C'est corrigé maintenant (même si je ne l'ai toujours pas testé). Le hashcode ne doit pas être non-collision tant que equals est implémenté correctement (après tout, tous les hashcodes d'une classe d'espace infini finissent par entrer en collision). –

2

Un exemple complet montrant Liste-de-Liste des collections et génériques (Java 1.5+)

// declare the list of lists 
List<List<String>> listOfListOfStrings = new ArrayList<List<String>>(); 

// populate 
List<String> listOfStrings = new ArrayList<String>(); // one inner list 
listOfStrings.add("one-one"); 
listOfStrings.add("one-two"); 
listOfListOfStrings.add(listOfStrings); 

listOfStrings = new ArrayList<String>(); // and another one 
listOfStrings.add("two-one"); 
listOfStrings.add("two-two"); 
listOfListOfStrings.add(listOfStrings); 

// access 
String oneOne = listOfListOfStrings.get(0).get(0); // first element of first inner list 
String twoTwo = listOfListOfStrings.get(1).get(1); // second element of second inner list 
+1

Le compilateur "pense" que 'add' est une classe à l'intérieur du paquet' listOfStrings' (ce qui est évidemment faux). 'listOfStrings' est une variable locale, la déclaration est juste en dessous du commentaire' // populate'. Vérifiez vos instructions d'importation et vérifiez que le code est dans une méthode. (avez-vous une classe nommée 'add'?) –

+0

J'ai trouvé l'erreur avant que j'ai vu votre commentaire. (Désolé de l'avoir supprimé.) J'avais mis le code par erreur sur la classe mais pas dans une méthode. Merci Andreas_D. – FILIaS

3

Bien qu'il soit certainement vrai que vous pouvez construire une liste < Liste < Liste < tout >>> en Java, je ne peux pas m'empêcher de me demander, Pourquoi voulez-vous faire cela? Non pas qu'il est inconcevable que ce soit la meilleure solution à votre problème, mais wow, comme pourquoi?

Je suppose que je pourrais imaginer quelque chose comme

public class Employee ... 
List<Employee> store; // all the employees in a store 
List<List<Employee>> city; // all the store lists for a city 
List<List<List<Employee>>> nation; // all the store lists for the nation 

Mais vous voulez vraiment le traiter de cette façon? Je ne sais pas, cela dépend de ce que vous devez faire avec.

Questions connexes