简体   繁体   中英

Java reading a CSV file's line and storing it into a List of Lists

I have a CSV file, looking like this:

First, Surname, Age    
Jim, Halpert, 35
Dwight, Schrute, 38

And I need to store it by Column (List of First names, list of surnames, list of ages). And I created a list of lists that would store this representation.

List<List<String>> myList = new ArrayList<List<String>>();
        while ((row = csvReader.readLine()) != null)
        {
            String[] myRow = row.split(",");
            for (int j=0; j<COLUMN_COUNT; j++)
            {
                myList.get(j).add(i,myRow[j]);
                System.out.println(data.get(j).get(i));

            }
            i++;
        }

My question is since I know what COLUMN_COUNT is, why doesn't this work? I am just trying to go through every line, and in every line, I separate the CSV to an array and then want to store this in a column-based list of lists.

The actual error I am getting is:

java.lang.IndexOutOfBoundsException: Index 0 out of bounds for length 0

and the error happens on the line myList.get(j)...

Thanks

Edit

Some of you suggested working examples, which now I am using, so thank you very much for that, Now, I am thinking that I might use Java Streams. so it would take less code and be more optimized: However when I do:

List<List<String>> myList = Files.lines(Path.of(csvPath)) // Stream<String>
                    //  .skip(1) // (optional) skip a header line
                    .map(line -> Arrays.stream(line.split("\\s*,\\s*")) // split by comma and trim whitespaces
                            .collect(Collectors.toList()) // get list of columns
                    ) // Stream<List<String>>
                    .collect(Collectors.toList());

I only get something like this as a result:

[Jim, Halpert, 35]
[Dwigth, Schrute, 38]

But I actually need

[Jim, Dwight]
[Helpert, Schrute]
[35,38]

Any suggestions? Thanks!

You have created myList but it is empty, it doesn't contains lists to handle values of each columns, you need to pre-fill it

// Add a list for each column
for (int j = 0; j < COLUMN_COUNT; j++) {
    myList.add(new ArrayList<>());
}

Then you may add the date, and you don't need an i to set the value in the sublist, just append it after the other values

while ((row = csvReader.readLine()) != null) {
    String[] myRow = row.split(",");
    for (int j = 0; j < COLUMN_COUNT; j++) {
        myList.get(j).add(myRow[j]);
    }
}

If the format of CSV file is simple (without double quoted strings, escaped commas, etc.), such file could be read in a simpler way using Stream API with new Files::lines method providing a stream of Strings:

List<List<String>> data = Files.lines(Path.of(csvFileName)) // Stream<String>
    //  .skip(1) // (optional) skip a header line
        .map(line -> Arrays.stream(line.split("\\s*,\\s*")) // split by comma and trim whitespaces
            .collect(Collectors.toList()) // get list of columns
        ) // Stream<List<String>>
        .collect(Collectors.toList());

Otherwise, appropriate library should be used to read CSV data like Apache Commons CSV


Update
In order to convert a stream of string lines/rows into columnar view List<List<String>> , the algorithm is as follows:

  1. Split each line by the delimiter into string array
  2. Convert each array into stream of map entries where key is a column index (use flatMap )
  3. Use collectingAndThen to collect incoming map entries into a map, and convert the latter into List<List<String>> :
static List<List<String>> toColumnList(Stream<String> lines) {
    return lines
        .map(line -> line.split("\\s*,\\s*")) // Stream<String[]>
        .flatMap(arr -> IntStream.range(0, arr.length)
            .mapToObj(i -> Map.entry(i, arr[i])) // Stream<Integer, String>, i - column index
        )
        .collect(Collectors.collectingAndThen(
            Collectors.groupingBy(
                Map.Entry::getKey, // group by column indexes
                Collectors.mapping(
                    Map.Entry::getValue, 
                    Collectors.toList()
            )), // Map<Integer, List<String>>
            map -> new ArrayList<>(map.values()) // convert map values to List<List<String>>
        ));
}

Test

System.out.println(toColumnList(
    Stream.of("John, Doe, 38", "Dwight, Wright, 45", "Jim, Beam, 40")
));

Output

[[John, Dwight, Jim], [Doe, Wright, Beam], [38, 45, 40]]

you will ned something like this

    int column_count = 3;
    List<List<String>> myList = new ArrayList<List<String>>();
    for (int i = 0; i < column_count; i++) {
        myList.add(new ArrayList<String>());
    }
    while ((row = csvReader.readLine()) != null){
        String[] split = row.split(",");
        for (int i = 0; i < split.length; i++) {
            myList.get(i).add(split[i]);
        }
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM