0

I asked a question some time back about parsing CSV files for a single matching row. In the example shown below, I use a bufferedreader to read the header row as the first step. Using this row, I parse the column names and then proceed to search for matching rows. The filter criteria I need to search for the matching row should be based on 2 column values, instead the code shown below only returns the 1 row - presumably because I use

.findFirst().get();

Instead I need something along the following lines (but this code is not valid)

List<String> rowCols = reader.lines()
 //.skip(1)
 .map((line) -> Arrays.asList(line.split(",")))
 .filter(list -> 
 !list.get(col1Index).equalsIgnoreCase("0:00") && 
 !list.get(col2Index).equalsIgnoreCase("0:00"))
 .findFirst().get();

as this also just returns 1 row - however the filter matches multiple rows.

I now need to return multiple matching rows but I cannot figure out the correct syntax.

String fileName = ...
try (BufferedReader reader = new BufferedReader(
 new InputStreamReader(ftpClient.
 retrieveFileStream(fileName)))){
 List<String> columns = reader.lines()
 .findFirst()
 .map(line -> Arrays.asList(line.split(",")))
 .get();
 // find the relevant sections from the CSV file
 // we are only interested in the row with the CA ServiceName
 int serviceNameIndex = columns.indexOf("ServiceName");
 int col1Index = columns.indexOf("Column1");
 int col2Index = columns.indexOf("Column2");
 // we need to know the index positions of the columns
 // also note that due to using a BufferedReader we don't
 // have to re-read the csv file to extract the values
 List<String> rowCols = reader.lines()
 //.skip(1)
 .map((line) -> Arrays.asList(line.split(",")))
 .filter(list -> list.get(serviceNameIndex).equalsIgnoreCase("service1"))
 .findFirst().get();
 EnumMap<Parameter, String> params = new EnumMap(Parameter.class) {{
 put(Parameter.ServiceName, rowCols.get(serviceNameIndex));
 put(Parameter.Column1, rowCols.get(col1Index));
 put(Parameter.Column2, rowCols.get(col2Index));
 }};
 params.put("service1", params);
}
asked Jun 16, 2016 at 17:13
3
  • 1
    Instead of calling .findFirst().get();, why are you not collecting the elements into a list with collect(Collectors.toList()) (since you want all rows)? Commented Jun 16, 2016 at 17:17
  • @Tunaki unfortunately that does not work unless I remove the map and filter lines (and then it just returns all rows except the header row which is not what I want. The map entry splits the current line into a list of col values that I need to filter on. It says something about inference variable T has incompatible bounds - equality constraints String, lower bounds: List<String> Commented Jun 16, 2016 at 17:26
  • 1
    @johnco3 "unfortunately that does not work unless I remove the map and filter line" what do you mean by that? What doesn't work, show what you've tried Commented Jun 16, 2016 at 21:18

2 Answers 2

3

I am not sure what you are trying to achieve exactly but my best guess is that you would like to return a list of strings based on the splitting of the line like line.split(","). Your code doesn't work because after your filter method you return the whole list of strings but you need to further stream the list. In other words you need to flatten the list to get its contents like below

List<String> rowCols = reader.lines()
 .map((line) -> Arrays.asList(line.split(",")))
 .filter(list -> 
 !list.get(col1Index).equalsIgnoreCase("0:00") && 
 !list.get(col2Index).equalsIgnoreCase("0:00"))
 .flatMap(e->e.stream())
 .collect(Collectors.toList());

This should collect the contents(strings which you've split) of each line into a single list.

answered Jun 16, 2016 at 21:44

Comments

2

I think you are expecting a List of string in a list to get all the matching rows. The below should work in that case:

 List<List<String>> rowCols = reader.lines()
 //.skip(1)
 .map((line) -> Arrays.asList(line.split(",")))
 .filter(list ->
 !list.get(col1Index).equalsIgnoreCase("0:00") &&
 !list.get(col2Index).equalsIgnoreCase("0:00"))
 .collect(Collectors.toList());

Edited as per comment by @Tunaki and @george

answered Jun 16, 2016 at 21:21

1 Comment

@Tunaki your guess was correct, one question though do you know how I might return a Map<String, EnumMap<Parameter, String>> to save a bit of post processing on the List<List<String>>. I am having a bit of trouble making the .collect(Collectors.toMap()); call the String part of the Map is just column 1 of the filtered results while the EnumMap should be just the mappings from Parameter.Column1 and Parameter.Column2) (slightly different than in my question where I alao include the serviceNameIndex (column 0) in the EnumMap. I know I should probably ask another question for this...

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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.