0

This is my arraylist

ArrayList<Courses> list = new ArrayList<Courses>();
list.add( new Courses(350,5/20/2020) );
list.add( new Courses(350,4/20/2019 );
list.add( new Courses(350,3/20/2018) );
list.add( new Courses(360,6/20/2020) );
list.add( new Courses(360,5/20/2019) );
list.add( new Courses(370,5/20/2020) );
list.add( new Courses(370,5/19/2018) );
list.add( new Courses(360,4/10/2016) );

public class Courses{
 int coursenum;
 Date date;

}

How can I remove elements so that the arraylist contains only those elements with the latest date?

Should like this;

350, 5/20/2020}
360,6/20/2020}
370, 5/20/2020
Nenna Anya
  • 67
  • 7
  • I recommend you don’t use `Date`. That class is poorly designed and long outdated. Instead use `LocalDate` from [java.time, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). – Ole V.V. Dec 16 '20 at 17:31

4 Answers4

1

Define a key date and remove all courses whose date is before your key date. Provided you have the appropriate getter:

ArrayList<Courses> list = new ArrayList<Courses>();
//populate list

Date someDate = new SimpleDateFormat("MM/dd/yyyy").parse("01/01/2020");

list.removeIf(c -> c.getDate().before(someDate));

Kindly @Randy Casburn has written a minimal yet complete example which I do not want to withhold from the interested reader:

/**
 *
 * @author Randy Casburn
 */
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class Main {

    public static void main(String[] args) {

        Date latest = new Date("1/1/2020");
        List<Courses> list = new ArrayList<>();
        list.add(new Courses(350, new Date("5/20/2020")));
        list.add(new Courses(350, new Date("4/20/2019")));
        list.add(new Courses(350, new Date("3/20/2018")));
        list.add(new Courses(360, new Date("6/20/2020")));
        list.add(new Courses(360, new Date("5/20/2019")));
        list.add(new Courses(370, new Date("5/20/2020")));
        list.add(new Courses(370, new Date("5/19/2018")));
        list.add(new Courses(360, new Date("4/10/2016")));

        list.removeIf(course -> !course.date.after(latest));
        list.forEach(l-> System.out.println(l.date));
    }
}

class Courses {
    int coursenum;
    Date date;
    Courses(int coursenum, Date date){
        this.coursenum = coursenum;
        this.date = date;
    }

}
Eritrean
  • 15,851
  • 3
  • 22
  • 28
1

I will recommend to use LocalDate from java-8, since Date is older version

public class Courses{
    int coursenum;
    LocalDate date;

  }

And then you can use removeIf

list.removeIf(d->d.isBefore(LocalDate.now());
Ryuzaki L
  • 37,302
  • 12
  • 68
  • 98
1

Java 1.7 and java.time through ThreeTen Backport

    ArrayList<Course> list = new ArrayList<>();
    list.add( new Course(350, "5/20/2020") );
    list.add( new Course(350, "4/20/2019") );
    list.add( new Course(350, "3/20/2018") );
    list.add( new Course(360, "6/20/2020") );
    list.add( new Course(360, "5/20/2019") );
    list.add( new Course(370, "5/20/2020") );
    list.add( new Course(370, "5/19/2018") );
    list.add( new Course(360, "4/10/2016") );
    
    // Find latest date for each course number
    Map<Integer, LocalDate> latestDates = new HashMap<>();
    for (Course currentCourse : list) {
        LocalDate latestHitherto = latestDates.get(currentCourse.getCourseNumber());
        if (latestHitherto == null || currentCourse.getDate().isAfter(latestHitherto)) {
            latestDates.put(currentCourse.getCourseNumber(), currentCourse.getDate());
        }
    }
    
    // Remove courses that haven’t got the latest date
    Iterator<Course> courseIterator = list.iterator();
    while (courseIterator.hasNext()) {
        Course currentCourse = courseIterator.next();
        if (currentCourse.getDate().isBefore(latestDates.get(currentCourse.getCourseNumber()))) {
            courseIterator.remove();
        }
    }
    
    // Print result
    for (Course currentCourse : list) {
        System.out.format("%3d %s%n", 
                currentCourse.getCourseNumber(), 
                currentCourse.getDate().format(Course.dateFormatter));
    }

Output from this snippet was:

350 5/20/2020
360 6/20/2020
370 5/20/2020

I ran on jdk1.7.0_67. I had added ThreeTen Backport 1.3.6. See the link below.

Here is the Course class I used:

public class Course {
    
    public static final DateTimeFormatter dateFormatter
            = DateTimeFormatter.ofPattern("M/d/u");
    
    private int courseNumber;
    private LocalDate date;
    
    public Course(int courseNumber, String dateString) {
        this.courseNumber = courseNumber;
        this.date = LocalDate.parse(dateString, dateFormatter);
    }

    public int getCourseNumber() {
        return courseNumber;
    }

    public LocalDate getDate() {
        return date;
    }
}

If you insist on using java.util.Date — a poorly designed and long outdated class — (1) I would not understand why you would, (2) you can probably modify my code to use Date instead.

Stream version

You may want consider upgrading your Java version. Java 15 is out, and an early access edition of Java 16. Already in Java 8 comes streams. They will allow you to obtain the same in much fewer lines of code:

    Collection<Course> filteredCourses = list.stream()
            .collect(Collectors.groupingBy(Course::getCourseNumber,
                    Collectors.collectingAndThen(Collectors.maxBy(Comparator.comparing(Course::getDate)),
                            Optional::orElseThrow)))
            .values();
    List<Course> filteredList = new ArrayList<>(filteredCourses);
    filteredList.forEach(c -> System.out.format(
            "%3d %s%n", c.getCourseNumber(), c.getDate().format(Course.dateFormatter)));
370 5/20/2020
360 6/20/2020
350 5/20/2020

As the code stands it doesn’t give the same order of courses in the resulting list, and it requires Java 10 (the overlaoded no-arg orElseThrow method was introduced there). Even if you require the same order, streams will still be extremely helpful.

Question: Can that work on Java 1.7?

java.time works nicely on both older and newer Android devices. It just requires at least Java 6.

  • In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in.
  • In non-Android Java 6 and 7 get the ThreeTen Backport, the backport of the modern classes (ThreeTen for JSR 310; see the links at the bottom).
  • On older Android either use desugaring or the Android edition of ThreeTen Backport. It’s called ThreeTenABP. In the latter case make sure you import the date and time classes from org.threeten.bp with subpackages.

Links

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
  • Nice answer! For future visitors, it can be improved for two things: (1) A full-fledged Java-8 solution can be added. This can have JSR 310 as well as features like `Collection#removeIf` (if required) etc. (2) A solution based on legacy API can be added. This is important because I can recall about two projects (in my career) in which clients rejected the idea of using 3rd party libraries which were not there in the already approved list. – Arvind Kumar Avinash Dec 17 '20 at 18:08
  • 1
    Thank you, @Arvind. I could write a much longer stream answer, have just added one example for now. For a way using the terrible classes from Java 1.0 and 1.1, (1) I don’t really consider it helpful to help users use those, (2) I already said that you can fairly easily substitute `Date` into my Java 1.7 code, that will have to suffice. Or you will have to write that solution in your own answer. Thanks for explaining why you often add such a solution in your answers. – Ole V.V. Dec 17 '20 at 19:56
0

I am attaching my code as an idea for you request. You can play around with it.

public class Courses {

    int courseNum;

    LocalDate date;

    public Courses(int courseNum, LocalDate date) {
        this.courseNum = courseNum;
        this.date = date;
    }

    public int getCourseNum() {
        return courseNum;
    }

    public void setCourseNum(int courseNum) {
        this.courseNum = courseNum;
    }

    public LocalDate getDate() {
        return date;
    }

    public void setDate(LocalDate date) {
        this.date = date;
    }

    @Override public String toString() {
        return new StringJoiner(", ", Courses.class.getSimpleName() + "[", "]")
                .add("courseNum=" + courseNum)
                .add("date=" + date)
                .toString();
    }

public class Main {
  public static void main(String[] args) {
        List<Courses> list = new ArrayList<>();
        list.add(new Courses(350, LocalDate.of(2020, 5, 20)));
        list.add(new Courses(350, LocalDate.of(2019, 4, 20)));
        list.add(new Courses(350, LocalDate.of(2018, 3, 20)));
        list.add(new Courses(360, LocalDate.of(2020, 6, 20)));
        list.add(new Courses(360, LocalDate.of(2019, 5, 20)));
        list.add(new Courses(370, LocalDate.of(2020, 5, 20)));
        list.add(new Courses(370, LocalDate.of(2018, 5, 19)));
        list.add(new Courses(360, LocalDate.of(2016, 4, 10)));

        List<Courses> res = list.stream().filter(c -> c.getDate().getYear() == 2020).collect(Collectors.toList());

        res.forEach(System.out::println);
    }
Echoinacup
  • 482
  • 4
  • 12
  • Is there a way to do it with something other than removeIf? I am using JDK 1.7. – Nenna Anya Dec 16 '20 at 19:53
  • @NennaAnya It can be done in Java 1.7, but a lot of things will be a lot easier if you can upgrade to a newer Java version. Java 15 is out, and early access version of Java 16. – Ole V.V. Dec 17 '20 at 07:08
  • 1
    @NennaAnya we are using filter here and not removeIf from Java 8. We can do it without filter. We can iterate over the array and do filter manipulations with it . – Echoinacup Dec 17 '20 at 09:44