Vivek Kothari
Vivek Kothari

Reputation: 472

How to convert a CSV file to List<Map<String,String>>

I have a CSV file which has a header in the first line. I want to convert it to List<Map<String, String>>, where each Map<String, String> in the list represents a record in the file. The key of the map is the header and the value is the actual value of the field. What I have so far:

BufferedReader br = <handle to file>;
// Get the headers to build the map.
String[] headers = br.lines().limit(1).collect(Collectors.toArray(size -> new String[size]));
Stream<String> recordStream = br.lines().skip(1);

What further operations can I perform on recordStream so that I can transform it to List<Map<String, String>>?

Sample CSV file is:

header1,header2,header3   ---- Header line
field11,field12,field13   ----> need to transform to Map where entry would be like header1:field11 header2:field12 and so on.
field21,field22,field23
field31,field32,field33

Finally all these Maps need to be collected to a List.

Upvotes: 3

Views: 8305

Answers (2)

Leo
Leo

Reputation: 1240

I know this is a bit of an old question, but I ran into the same problem, and created a quick sample of the Commons CSV solution mentioned by Tagir Valeev:

            Reader in = new FileReader("path/to/file.csv");
            Iterable<CSVRecord> records = CSVFormat.RFC4180.withFirstRecordAsHeader().parse(in);

            List<Map> listOfMaps = new ArrayList<>();
            for (CSVRecord record : records) {
                listOfMaps.add(record.toMap());
            }

Upvotes: 2

Tunaki
Tunaki

Reputation: 137064

The following will work. The header line is retrieved by calling readLine directly on the BufferedReader and by splitting around ,. Then, the rest of the file is read: each line is split around , and mapped to a Map with the corresponding header.

try (BufferedReader br = new BufferedReader(...)) {
    String[] headers = br.readLine().split(",");
    List<Map<String, String>> records = 
            br.lines().map(s -> s.split(","))
                      .map(t -> IntStream.range(0, t.length)
                                         .boxed()
                                         .collect(toMap(i -> headers[i], i -> t[i])))
                      .collect(toList());
    System.out.println(headers);
    System.out.println(records);
};

A very important note here is that BufferedReader.lines() does not return a fresh Stream when it is called: we must not skip 1 line after we read the header since the reader will already have advanced to the next line.

As a side note, I used a try-with-resources construct so that the BufferedReader can be properly closed.

Upvotes: 9

Related Questions