Streams filter and Grouping List on Map

Viewed 92

I am making a filter that allows me to generate a Map whose values are lists of files, for this, I have tried to use Streams. I have the following example of Files list:

  • CLA_FileName
  • CLA_FileName
  • CLA_FileName
  • CM_FileName
  • CM_FileName
  • CM_FileName
  • SP_FileName
  • SP_FileName
  • CON_FileName
  • CON_FileName

Then I need to take that list of files and take them to a map whose key groups all the files of a type within a single list;

Map <String, List < File>>: So this would be the expected result.

 "CLA_", List <File> 3 CLA Files
 "CM_",  List <File> 3 CM Files
 "SP_",  List <File> 2 SP Files
 "CON_", List <File> 2 CON Files

I have the following code, which is only grouping one file type for me, CLA. Please can you give me an idea of how to filter and load these files on the Map?

List<File> csvList = getFiles();

Function<File, String> filterCLA = new Function<File, String>() {
    @Override
    public String apply(File file) {
        return String.valueOf(file.getName().startsWith("CLA_"));
    }
};

Map<String, List<File>> map = csvList.stream()
        .collect(groupingBy(f-> filterCLA.apply(f), toCollection(ArrayList::new)));


for(Map.Entry<String, List<File>> entry: map.entrySet()){
    System.out.println(entry.getKey()+" - "+ entry.getValue());
}

This code is only saving the CLA files in a list within the map, with CLA_ key. This is correct but I need to add the rest of the files.

2 Answers

Try this. Any filename that does not begin with something like XXX_ will be mapped to a catch all key of type UnknownType

List<File> csvList = List.of(
new File("CLA_FileName"),
new File("CLA_FileName"),
new File("CLA_FileName"),
new File("CM_FileName"),
new File("CM_FileName"),
new File("CM_FileName"),
new File("SP_FileName"),
new File("SP_FileName"),
new File("CON_FileName"),
new File("CON_FileName"),
new File("BadFileName1"),
new File("BadFileName2"));
        

// get the prefix (e.g. CM_)
Function<File, String> getPrefix  = f-> {
       String name = f.getName();
    // location of delimiter
    int index = name.indexOf('_');
    if (index < 0) {
      return "UNKNOWN_TYPE";
    }
    return name.substring(0,index+1);
};
    
// create the map
Map<String, List<File>> map = csvList.stream()
        .collect(Collectors.groupingBy(getPrefix));

//print the map
map.entrySet().forEach(System.out::println);

Prints

UNKNOWN_TYPE - [BadFileName1, BadFileName2]
CON_ - [CON_FileName, CON_FileName]
SP_ - [SP_FileName, SP_FileName]
CM_ - [CM_FileName, CM_FileName, CM_FileName]
CLA_ - [CLA_FileName, CLA_FileName, CLA_FileName]

Finally I was able to find a solution to filter and group. Here the code. Thanks everyone for your help

    List<Predicate<File>> allPredicates = new ArrayList<Predicate<File>>();
    allPredicates.add(str -> str.getName().startsWith("CM"));
    allPredicates.add(str -> str.getName().startsWith("CLA"));
    allPredicates.add(str -> str.getName().startsWith("IDP"));
    allPredicates.add(str -> str.getName().startsWith("SP"));
    allPredicates.add(str -> str.getName().startsWith("CON"));

    return Arrays.asList(csvFiles)
                    .stream()
                    .filter(allPredicates.stream().reduce(f->true, Predicate::or))
                    .collect(Collectors.groupingBy(f-> f.getName().substring(0,f.getName().indexOf("_"))));
Related