2

I have list of records as below. I want to fetch the latest record based on date and set its name as 'H'. In the same way I want to set 'L' as name for all remaining records.

List<Student> studentList = new ArrayList<>();

try {
  studentList.add(new Student("A", new SimpleDateFormat("dd-MM-yyyy").parse("01-01-1990")));
  studentList.add(new Student("B", new SimpleDateFormat("dd-MM-yyyy").parse("01-01-2010")));
  studentList.add(new Student("C", new SimpleDateFormat("dd-MM-yyyy").parse("01-01-2011")));
  studentList.add(new Student("D", new SimpleDateFormat("dd-MM-yyyy").parse("01-01-2012")));
  studentList.add(new Student("E", new SimpleDateFormat("dd-MM-yyyy").parse("01-01-2018")));

} catch (ParseException e) {
  // TODO Auto-generated catch block
  e.printStackTrace();  
}

Student student = Collections.max(studentList, Comparator.comparing(s -> s.getDate()));

I've tried as above but here I can set name only for latest record but I'm unable to set name for all other remaining records.

Any help would be appreciated.

Ryuzaki L
  • 37,302
  • 12
  • 68
  • 98
Raj Raichand
  • 97
  • 2
  • 9
  • why not trim the size, and get the last index? – Stultuske Oct 24 '19 at 09:25
  • 1
    why not just sort the Collection and set `H` for one and `L` for the rest of them? – Naman Oct 24 '19 at 09:29
  • 1
    what if two students have the same date that is the max in sorting, which one would you set as `H` and which as `L`? – Naman Oct 24 '19 at 10:25
  • I recommend you don’t use `SimpleDateFormat` and `Date`. Those classes are poorly designed and long outdated, the former in particular notoriously troublesome. Instead use `LocalDate` and `DateTimeFormatter`, both from [java.time, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). – Ole V.V. Oct 24 '19 at 20:05

3 Answers3

4

Single-threaded version:

// Find the latest student in the list 
Student latest = Collections.max(studentList,
                                 Comparator.comparing(s -> s.getDate()));

// Iterate the list, setting each student's name depending on whether it
// is the latest or not. 
studentList.forEach(s -> {s.setName(s == latest ? "H" : "L");});

The above code makes two passes through the list. There are other ways to do the second step; e.g.

studentList.forEach(s -> {s.setName("L");});
latest.setName("H");

The max call will throw NoSuchElementException if the collection is empty. You could either treat that as an error (i.e. let the exception propagate), or test for an empty list before you start.


A one pass solution is possible using streams:

Optional<Student> latest = studentList.stream()
                .peek(s -> {s.setName("L")})
                .max(Comparator.comparing(s -> s.getDate());
latest.ifPresent(s -> {s.setName("H")});

We set every student's name to "L" and find the latest in one pass. Then we reset the latest student's name to "H".

This version also works for an empty list. (Indeed, we would need to work hard to make it not work. Optional is helpful in some contexts.)

If the list was long enough, might be worth using parallel().

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
2

If you have only date please use LocalDate and DateTimeFormatter from java-8

studentList.add(new Student("A", LocalDate.parse("01-01-1990", DateTimeFormatter.ofPattern("dd-MM-yyyy")));

So the Student class will be

public class Student {

    private String name;
    private date LocalDate;

    //getters and setters

   }

Now use Collections.max Since LocalDate implements Comparable

Student student =  Collections.max(studentList, Comparator.comparing(s -> s.getDate()));

To Set H and L

1st aaproach

The approach i would suggest here is first set name = L for every student using forEach

studentList.forEcah(stu->stu.setName("L"));

Now just get the max student using comparator and set name = H

Student student =  Collections.max(studentList, Comparator.comparing(s -> s.getDate()));
student.setName("H");

2nd approach

You can sort the List first

studentList.sort(Comparator.comparing(s -> s.getDate()).reversed());

And then Set name = H for first record and L for rest of them

IntStream.range(0,studentList.size())
         .forEach(i->{
              if(i==0) {
                 studentList.get(i).setName("H");
                }
                else {
               studentList.get(i).setName("L");
               }
             });
Ryuzaki L
  • 37,302
  • 12
  • 68
  • 98
  • from the question - *i tried as above but here i can set name only for latest record where as i am unable to set name for all other remaining records?* – Naman Oct 24 '19 at 09:34
  • I didn’t understand your question, @Naman. The answer shows how to set the name to `L` on all other remaining records. – Ole V.V. Oct 24 '19 at 20:10
0

Just iterate over your list and set the name as you need:

Student student = Collections.max(studentList, Comparator.comparing(Student::getDate));
studentList.forEach(s -> s.name = s.equals(student) ? "H" : "L");
Roger Kreft
  • 200
  • 10
  • Of course the printing is not neccessary. I was hoping that would be obvious, but you might be right that not everyone knows that. Edited, thanks... – Roger Kreft Oct 25 '19 at 06:30