Reputation: 65
I'm trying to code a multilevel filter. I have folders and files.
public class Folder {
String name;
List<Folder> folders;
List<File> files;
...
}
public class File {
String name;
String type;
...
}
I need a filter who looks for some property e.g. name, which can be a folder/file name. I wrote a piece of code that works for one level, but I don't how could I do that looking for two level loops.
The final result would be a list of folders: the ones which names match the 'name filter' or folders which file names match the filter.
List<Folder> result = folders.stream()
.filter(folder -> folder.getFiles().stream().anyMatch(file -> file.getName().contains(filter)))
.collect(Collectors.toList());
Upvotes: 2
Views: 898
Reputation: 1150
A running test which filters by filename across folders (without any helper method).
The predicate in your filter method is what makes the difference alongside flatMap as @Ernest refers to that flattens all the File elements into one list.
private static final String FILE_NAME_FILTER = "1";
private static final String HOME_FOLDER_FILTER = "home";
private static final String VAR_FOLDER_FILTER = "var";
private static final String BIN_FOLDER_FILTER = "bin";
@Test
public void test() {
File f1 = new File("1", "txt");
File f2 = new File("1", "json");
File f3 = new File("1", "yml");
File f4 = new File("4", "doc");
Folder folder1 = new Folder(HOME_FOLDER_FILTER, asList(f1, f2));
Folder folder2 = new Folder(VAR_FOLDER_FILTER, asList(f2, f3));
Folder folder3 = new Folder(BIN_FOLDER_FILTER, asList(f3, f4));
List<Folder> folders = asList(folder1, folder2, folder3);
List<File> files = folders.stream()
.filter(folder -> folder.getName().equals(HOME_FOLDER_FILTER))
.map(Folder::getFiles) // no helper method
.flatMap(List::stream)
.filter(file -> file.getName().equals(FILE_NAME_FILTER))
.collect(Collectors.toList());
Assert.assertEquals(2, files.size());
}
Pretty much along the line of what @Oleksandr suggests.
Edit: I see i missed out on the fact that a folder can contain a folder. Should I delete this answer?
Upvotes: 0
Reputation: 16226
I think it will be better to add a helper method to the Folder class that will flatten nested folders into a Stream recursively:
class Folder {
String name;
List<Folder> folders;
List<File> files;
Stream<Folder> flatten() {
return Stream.concat(Stream.of(this), folders.stream().flatMap(Folder::flatten));
}
}
After that, you can get the final result using flatMap(...)
List<Folder> result = folders.stream()
.flatMap(Folder::flatten)
.filter(folder -> folder.getFiles()
.stream()
.anyMatch(file -> file.getName().contains(filter)))
.collect(Collectors.toList());
Upvotes: 3