0

Input (CSV File)

Header1,Header2,Header3

Data1,Data2,Data3

Data4,Data5,Data6

Data7,,

,,Data8

I am trying to parse through a CSV file similar to the above structure and store the data into a Map<String (Row Number), Map<String (Column Header), String (Column Value)>>.

1
  • 1
    Use a CSV API such as OpenCsv Commented Jan 11, 2023 at 20:09

1 Answer 1

1

Assuming your file is well formed and each row has the same column count as your header, something like below migght be a starting point:

import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public final class Example {

    public static void main(String[] args) throws IOException {

        //create a map    
        Map<String, Map<String, String>> map = new LinkedHashMap<>();

        Path filePath = Paths.get("path to your/test.csv");
        Charset charset = StandardCharsets.UTF_8;

        //read the file
        List<String> fileContent = Files.readAllLines(filePath, charset);

        // get the header
        String[] header = fileContent.get(0).split(",");

        AtomicInteger lineNumber = new AtomicInteger(1);

        //fill the map
        fileContent.stream()
                   .skip(1)
                   .forEach(line -> map.put(
                           String.valueOf(lineNumber.getAndIncrement()),
                           getRowData(header, line.split(","))));

        System.out.println(map);
    }

    // helper method to make the filling of the map in the stream readable
    private static Map<String, String> getRowData(final String[] header, final String[] line) {
        return IntStream.range(0, header.length)
                        .mapToObj(i -> Map.entry(header[i], line[i]))
                        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
    }
}
Sign up to request clarification or add additional context in comments.

3 Comments

Yes, each row will always match the column count for the header. There might be some null or empty values here and there. But most of them will be populated. Thank you
Index 53 out of bounds for length 53 java.lang.ArrayIndexOutOfBoundsException: Index 53 out of bounds for length 53 I am getting this error when I am trying to retrieve the code. So, when you meant that the row should have the same column count as the header. Does each and every row needs to be populated?
@stubbledweb1995 depends on what the disired behavior in such a case should be. Do you want to ignore that line, throw an exception, fill with a default value or keep it as an empty string ...? if you want to keep the empty strings just use the split method with a limit parameter -1 like : getRowData(header, line.split(",", -1))

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.