web-dev-qa-db-fra.com

Travailler avec une liste de listes en Java

J'essaie de lire un fichier CSV dans une liste de listes (de chaînes), de le transmettre pour obtenir des données d'une base de données, de créer une nouvelle liste de listes de nouvelles données, puis de transmettre cette liste de listes pour qu'elle puisse être écrit dans un nouveau fichier CSV. J'ai regardé partout, et je n'arrive pas à trouver un exemple sur la façon de le faire

Je préfère ne pas utiliser de tableaux simples car la taille des fichiers varie et je ne saurai pas quoi utiliser pour les dimensions des tableaux. Je n'ai aucun problème avec les fichiers. Je ne suis tout simplement pas sûr de savoir comment traiter la liste de listes.

La plupart des exemples que j'ai trouvés vont créer des tableaux multidimensionnels ou effectuer des actions dans la boucle qui lisent les données du fichier. Je sais que je peux le faire, mais je veux écrire du code orienté objet. Si vous pouviez fournir un exemple de code ou m'indiquer une référence, ce serait formidable.

45
Rob-0
ArrayList<ArrayList<String>> listOLists = new ArrayList<ArrayList<String>>();
ArrayList<String> singleList = new ArrayList<String>();
singleList.add("hello");
singleList.add("world");
listOLists.add(singleList);

ArrayList<String> anotherList = new ArrayList<String>();
anotherList.add("this is another list");
listOLists.add(anotherList);
117
tster

Si vous voulez vraiment savoir que les fichiers CSV gèrent parfaitement en Java, il n’est pas bon d’essayer d’implémenter un lecteur/graveur CSV par vous-même. Vérifiez ci-dessous. 

http://opencsv.sourceforge.net/

Lorsque votre document CSV inclut des guillemets ou des nouvelles lignes, vous devrez faire face à des difficultés. 

Pour apprendre l’approche orientée objet au début, voir l’implémentation d’autres implémentations (par Java) vous aidera. Et je pense que ce n'est pas un bon moyen de gérer une ligne dans une liste. CSV ne vous permet pas d'avoir une différence de taille de colonne. 

15
xrath

Voici un exemple qui lit une liste de chaînes CSV dans une liste de listes, puis parcourt cette liste de listes et imprime les chaînes CSV sur la console.

import Java.util.ArrayList;
import Java.util.List;

public class ListExample
{
    public static void main(final String[] args)
    {
        //sample CSV strings...pretend they came from a file
        String[] csvStrings = new String[] {
                "abc,def,ghi,jkl,mno",
                "pqr,stu,vwx,yz",
                "123,345,678,90"
        };

        List<List<String>> csvList = new ArrayList<List<String>>();

        //pretend you're looping through lines in a file here
        for(String line : csvStrings)
        {
            String[] linePieces = line.split(",");
            List<String> csvPieces = new ArrayList<String>(linePieces.length);
            for(String piece : linePieces)
            {
                csvPieces.add(piece);
            }
            csvList.add(csvPieces);
        }

        //write the CSV back out to the console
        for(List<String> csv : csvList)
        {
            //dumb logic to place the commas correctly
            if(!csv.isEmpty())
            {
                System.out.print(csv.get(0));
                for(int i=1; i < csv.size(); i++)
                {
                    System.out.print("," + csv.get(i));
                }
            }
            System.out.print("\n");
        }
    }
}

Assez simple, je pense. Quelques points à noter:

  1. Je recommande d'utiliser "Liste" au lieu de "ArrayList" sur le côté gauche lors de la création d'objets de liste. Il est préférable de faire passer l'interface "Liste" car si vous devez utiliser ultérieurement quelque chose comme Vector (par exemple, vous avez maintenant besoin de listes synchronisées), il vous suffit de modifier la ligne avec la nouvelle instruction. Quelle que soit l’implémentation de la liste que vous utilisez, par exemple Vector ou ArrayList, vous passez toujours toujours List<String>.

  2. Dans le constructeur ArrayList, vous pouvez laisser la liste vide. Elle aura par défaut une certaine taille, puis se développera dynamiquement en fonction des besoins. Mais si vous connaissez la taille de votre liste, vous pouvez parfois enregistrer certaines performances. Par exemple, si vous saviez qu'il y aura toujours 500 lignes dans votre fichier, vous pouvez faire:

List<List<String>> csvList = new ArrayList<List<String>>(500);

De cette façon, vous ne perdriez jamais de temps de traitement à attendre que votre liste grandisse de façon dynamique. C'est pourquoi je passe "linePieces.length" au constructeur. Ce n'est généralement pas grave, mais utile parfois.

J'espère que cela pourra aider!

10
Brent Writes Code

L'exemple fourni par @tster montre comment créer une liste de liste. Je vais donner un exemple pour parcourir une telle liste.

Iterator<List<String>> iter = listOlist.iterator();
while(iter.hasNext()){
    Iterator<String> siter = iter.next().iterator();
    while(siter.hasNext()){
         String s = siter.next();
         System.out.println(s);
     }
}
5
Vincent Ramdhanie

Quelque chose comme ça fonctionnerait pour la lecture:

String filename = "something.csv";
BufferedReader input = null;
List<List<String>> csvData = new ArrayList<List<String>>();
try 
{
    input =  new BufferedReader(new FileReader(filename));
    String line = null;
    while (( line = input.readLine()) != null)
    {
        String[] data = line.split(",");
        csvData.add(Arrays.toList(data));
    }
}
catch (Exception ex)
{
      ex.printStackTrace();
}
finally 
{
    if(input != null)
    {
        input.close();
    }
}
3
Droo

J'ajouterai à ce que xrath a dit: mieux vaut utiliser une bibliothèque existante pour gérer la lecture/écriture au format CSV.

Si vous envisagez de lancer votre propre framework, je vous suggérerais également de ne pas utiliser List<List<String>> comme implémentation. Mieux vaut probablement implémenter les classes CSVDocument et CSVRow (qui peuvent utiliser en interne un List<CSVRow> ou un List<String> respectivement), bien que pour les utilisateurs, exposer uniquement une liste immuable ou un tableau. 

Le simple fait d'utiliser List<List<String>> laisse trop de cas Edge non vérifiés et repose sur des détails d'implémentation - comme, les en-têtes sont-ils stockés séparément des données? ou sont-ils dans la première ligne du List<List<String>>? Que faire si je veux accéder aux données par en-tête de colonne à partir de la ligne plutôt que par index?

que se passe-t-il lorsque vous appelez des choses comme:

// reads CSV data, 5 rows, 5 columns 
List<List<String>> csvData = readCSVData(); 
csvData.get(1).add("extraDataAfterColumn"); 
// now row 1 has a value in (nonexistant) column 6
csvData.get(2).remove(3); 
// values in columns 4 and 5 moved to columns 3 and 4, 
// attempting to access column 5 now throws an IndexOutOfBoundsException.

Vous pouvez essayer de valider tout cela en écrivant le fichier CSV, et cela peut fonctionner dans certains cas ... mais dans d'autres cas, vous avertirez l'utilisateur d'une exception très éloignée du lieu où la modification erronée a été effectuée, ce qui entraîne débogage difficile.

2
Nate

Voici également un exemple de la façon d’imprimer une liste de listes en utilisant advanced for for:

public static void main(String[] args){
        int[] a={1,3, 7, 8, 3, 9, 2, 4, 10};
        List<List<Integer>> triplets;
        triplets=sumOfThreeNaive(a, 13);
        for (List<Integer> list : triplets){
            for (int triplet: list){
                System.out.print(triplet+" ");
            }
            System.out.println();
        }
    }
0
Mona Jalal