2009-09-25 17 views
36

Estoy tratando de leer un archivo CSV en una lista de cadenas (lista de cadenas), pasarlo para obtener datos de una base de datos, crear una nueva lista de listas de datos nuevos , luego pase esa lista de listas para que pueda escribirse en un nuevo archivo CSV. He buscado por todos lados, y parece que no puedo encontrar un ejemplo sobre cómo hacerlo.Trabajando con una lista de listas en Java

Preferiría no utilizar arreglos simples ya que los archivos variarán en tamaño y no sabré qué usar para las dimensiones de las matrices. No tengo problemas para tratar con los archivos. Simplemente no estoy seguro de cómo lidiar con la lista de listas.

La mayoría de los ejemplos que he encontrado creará matrices multidimensionales o realizará acciones dentro del bucle que está leyendo los datos del archivo. Sé que puedo hacerlo, pero quiero escribir código orientado a objetos. Si pudiera proporcionar algún código de ejemplo o señalarme una referencia, sería genial.

Respuesta

105
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); 
9

Aquí hay un ejemplo que lee una lista de cadenas CSV en una lista de listas y después se coloca a través de esa lista de listas y de la parte posterior de las cadenas CSV en la consola.

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"); 
     } 
    } 
} 

Bastante sencillo, creo. Sólo un par de puntos de aviso:

  1. recomiendo el uso de "lista" en lugar de "ArrayList" en el lado izquierdo al crear objetos de la lista. Es mejor pasar alrededor de la interfaz "Lista" porque luego, si necesita cambiar a usar algo como Vector (por ejemplo, ahora necesita listas sincronizadas), solo necesita cambiar la línea con la declaración "nueva". No importa la implementación de la lista que use, p. Vector o ArrayList, usted siempre acaba de pasar alrededor de List<String>.

  2. En el constructor ArrayList, puede dejar la lista vacía y tendrá un tamaño predeterminado y luego crecer dinámicamente según sea necesario. Pero si sabe cuán grande puede ser su lista, a veces puede ahorrar algo de rendimiento. Por ejemplo, si usted sabía que había siempre va a ser de 500 líneas en su archivo, entonces se podría hacer:

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

esa manera que nunca se pierda el tiempo de procesamiento a la espera de su lista para crecer dinámicamente crecer. Es por eso que paso "linePieces.length" al constructor. No suele ser un gran problema, pero a veces es útil.

Espero que ayude!

+2

Su ejemplo, si bien bastante detallado, es también bastante engañoso. Leer un archivo CSV línea por línea y dividir líneas en coma sin tener en cuenta las comillas circundantes es un problema. – ChssPly76

+2

Estoy de acuerdo con usted y con todos los demás acerca de CSV no es tan simple como simplemente dividir en comas. Me dio la impresión de que el quid de la cuestión era demostrar cómo usar genéricos y listas de listas, no analizar CSV. Me gusta OpenCSV como un paquete, así que definitivamente estoy de acuerdo con usted y con todos los demás y recomiendo algo así para el análisis de las líneas. ¡Gracias por la respuesta! –

5

El ejemplo proporcionado por @tster muestra cómo crear una lista de listas. Proporcionaré un ejemplo para iterar sobre dicha lista.

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); 
    } 
} 
14

Si está realmente como para saber que manejar archivos CSV perfectamente en Java, que no es bueno para tratar de implementar CSV de lectura/escritura por sí mismo. Verifique abajo.

http://opencsv.sourceforge.net/

Cuando el documento CSV incluye entre comillas dobles o saltos de línea, que se enfrentará a dificultades.

Para aprender el enfoque orientado a objetos al principio, ver otra implementación (por Java) le ayudará. Y creo que no es una buena forma de administrar una fila en una lista.CSV no le permite tener un tamaño de columna de diferencia.

+17

+1 por sugerir OpenCSV. Sin embargo, ** es ** bueno intentar * implementar usted mismo el lector/escritor CSV, especialmente para un novato de Java: aprende muchas cosas en el camino. – ChssPly76

2

Recuérdame lo que dijo xrath: es mejor que utilices una biblioteca existente para manejar leer/escribir CSV.

Si planea rodar su propio marco, yo tampoco sugerir el uso de List<List<String>> como su aplicación - que probablemente sería mejor implementar CSVDocument y CSVRow clases (que puede internamente utiliza un List<CSVRow> o List<String> respectivamente), aunque para los usuarios, solo exponga una lista inmutable o una matriz.

Simplemente usando List<List<String>> deja demasiadas cajas de borde sin control y confiando en detalles de implementación - como, ¿los encabezados están almacenados por separado de los datos? o están en la primera fila del List<List<String>>? ¿Qué pasa si quiero acceder a los datos por encabezado de columna desde la fila en lugar de por índice?

lo que sucede cuando se llama a cosas como:

// 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. 

Se podría intentar validar todo esto al escribir el archivo CSV, y esto puede funcionar en algunos casos ... pero en otros, se le alertar al usuario de una excepción lejos de donde se realizó el cambio erróneo, lo que resulta en una depuración difícil.

3

Algo como esto funcionaría para la lectura:

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(); 
    } 
} 
0

También este es un ejemplo de cómo imprimir la lista de la lista con la avanzada de bucle:

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(); 
     } 
    } 
Cuestiones relacionadas