3

I'm trying to use Lambda expressions in my Java project. My code reads files from a folder, stores them in an array and sorts them in descending order. Other methods will use this code to get the file that contains most recent date.

Arrays.sort(listOfFiles, (File file1, File file2) -> file2.getName().compareToIgnoreCase(file1.getName()));

The output is:

README.txt
forecast-project-export-from-2017-03-06-to-2017-03-10.csv
forecast-project-export-from-2017-02-27-to-2017-03-03.csv
forecast-project-export-from-2017-02-20-to-2017-02-24.csv
forecast-project-export-from-2017-02-13-to-2017-02-17.csv
forecast-project-export-from-2017-02-06-to-2017-02-10.csv
forecast-project-export-from-2017-01-30-to-2017-02-03.csv
forecast-project-export-from-2017-01-23-to-2017-01-27.csv

The output is correct however, the folder contains a README.txt file which I want to Ignore or not have it as element[0] of the array. Is there a way I can use an if statement that only sorts elements if their name contains "forecast-project-export-from". Something like this:

if (o1.getName().contains("forecast-project-export-from") && o2.getName().contains("forecast-project-export-from")) {
     return o2.getName().compareToIgnoreCase(o1.getName());
}
5
  • 1
    You can use if, but that won't help you with your file. you need to remove your file from the actual input. You can use streams to sort it like this: tmp.stream().filter( x -> x.startsWith("my-prefix")).sorted( (k1, k2) -> k1.compareTo(k2)).collect(Collectors.toList()); Commented Mar 17, 2017 at 15:26
  • I think you can filter your listOfFiles for removing unused files and then sort list. Commented Mar 17, 2017 at 15:26
  • though you mention excluding the README.txt file, it sounds like what you actually want to do is only include files that match the pattern forecast-project-export-from-<date>-to-<date>.csv. Currently README.txt in the only problem file, but if you only exclude that file, then if another "bad" file was added to the folder, your code would likely break again. So, the filter examples given are a good starting point, but I'd do an inclusive filter for files you want, rather than exclusive for the currently known one you don't. Commented Mar 18, 2017 at 9:23
  • Also, how are you getting the list of files? As there's also the potential of filtering at that point, for example: folder.list((dir, filename) -> filename.matches("forecast-project-export-from-\\d{4}-\\d{2}-\\d{2}-to-\\d{4}-\\d{2}-\\d{2}\\.csv")); Commented Mar 18, 2017 at 9:25
  • @lukens I used Paul's code to filter out the file, If there's a file with a different name, it's ok, I just don't want it to be the 0th element of the array. The reason for that is my other methods want to get file with the latest dates to do some processing. The files are downloaded using Selenium WebDriver in a separate project and Jenkins copies those files into current directory Commented Mar 18, 2017 at 18:59

3 Answers 3

2

Altering a Comparator for this purpose can work, if you're content with storing the read-me as the last value in the array.

(File file1, File file2) -> {
    if(file1.getName().equals("README.txt"))
         return 1;  //readme-file is always "greater" than other files
    if(file2.getName().equals("README.txt"))
         return -1;
    else 
        return file2.getName().compareToIgnoreCase(file1.getName()));
 };

Relevant jls-section

If you want to eliminate the README-file however, you'll have to filter it out (we all love Java8, so here's the stream version):

File[] sorted = Arrays.stream(listOfFiles).filter(f->!f.getName().equals("README.txt")).
    sort(Comparator.comparing(File::getName, String::compareToIgnoreCase)).
    toArray(File[]::new);
Sign up to request clarification or add additional context in comments.

7 Comments

Wouldn't your stream example result in a stream with only one readme file?
@Sylwester sry, my bad. I'll correct that. Thanks for pointing it out :)
Shouldn't that be .sorted(Comparator.comparing(File::getName) ?
You might update sort(Comparator.comparing(File::getName)) to sorted(Comparator.comparing(File::getName, String::compareToIgnoreCase))
@pratikpncl doesn't exactly matter. It's shorter (and I've already updated the answer a few minutes ago with that), but technically it won't change the behavior, as the same function will be used for the comparison. It's just more verbose (unnecessarily)
|
2

Deleting an element from a collection during sorting is not possible.

You can now provide a FileFilter as lambda expression when listing the files in a folder:

File.listFiles(f -> f.getName().equals("README.txt"));

By the way: Sorting element by using an extractor is way more elegant (IMHO):

listOfFiles.sort(Comparator.comparing(File::getName));

Comments

1

Sorting the array is not enough to get rid of the README.txt, you will need to filter

after sorting you will need:

List<File> result = Arrays.asStream(listOfFiles)            
    .filter(x -> !"readme.txt".equalsIgnoreCase(x.getName()))   
    .collect(Collectors.toList());          

result.forEach(System.out::println);

Comments

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.