2

I'd like to sort list of my objects by one argument it's date in format "YYYY-MM-DD HH:mm" by ascending order. I can't find a right solution. In python It's easily to sort it using lambda, but in Java I've a problem with it.

for (Shop car : cars) {
             Collections.sort(cars, new Comparator<Shop>() {
                @Override
                public int compare(final Shop car, final Shop car) {
                    return car.getDate().compareTo(arc.getDate());
            }
        });

Thanks in advance!

stackish
  • 49
  • 1
  • 2
  • 6
  • is it a date or string of that type? if it is a date which java object do you use? – strash Apr 15 '17 at 13:36
  • It's a string of that type – stackish Apr 15 '17 at 13:37
  • Show some actual code of what you've tried. Is this Java 8? if not that's very important. – Novaterata Apr 15 '17 at 13:37
  • I've only list of data objects of myOwnClass, and used Collection.sort(thatList); – stackish Apr 15 '17 at 13:39
  • But it doesn't work – stackish Apr 15 '17 at 13:39
  • check my updated answer and please tell me if it works because I dont have test data here – strash Apr 15 '17 at 14:18
  • Ok please wait a moment – stackish Apr 15 '17 at 14:27
  • Using the two-arg `Collections.sort()` is a good idea. You don’t want to do it in a loop. Other than this and a typo in the parameter list, your code should work. You shouldn’t have `car` twice in `(final Shop car, final Shop car)`, you probably meant `arc` the second time. – Ole V.V. Apr 15 '17 at 18:54
  • 1
    Tip: Use only the java.time classes, never the `Date` & `Calendar` classes. – Basil Bourque Apr 15 '17 at 18:59
  • On one hand the asker doesn’t need any date-time classes at all since the natural ordering of the strings is the order s/he wants. On the other hand, for most purposes it would probably be more convenient to store the date as a `java.time.LocalDateTime` inside the `Shop` object. Also @BasilBourque – Ole V.V. Apr 15 '17 at 19:04
  • @stackish, in the question you write that the dates have format `yyyy-MM-dd HH:mm`, but in comments to a couple of the answers you say it’s `yyyy-MM-dd` only. You are not making it easy to help you with a working solution. No matter which is correct I still mean what I’ve said in my two previous comments though (except if you don’t want to have hours and minutes, it should be `LocalDate` rather than `LocalDateTime`). – Ole V.V. Apr 16 '17 at 17:33

5 Answers5

3

public boolean before(Date when)

true if and only if the instant of time represented by this Date object is strictly earlier than the instant represented by when; false otherwise.

please refer java docs for more info https://docs.oracle.com/javase/8/docs/api/java/util/Date.html#before-java.util.Date-

Or you can use after method from Date Class inplace of before

package com.stackoverflow.DataSortReverse;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;

class Car{
    private String name;
    private Date date;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Date getDate() {
        return date;
    }
    public void setDate(Date date) {
        this.date = date;
    }
    public Car(String name, Date date) {
        super();
        this.name = name;
        this.date = date;
    }
    @Override
    public String toString() {
        return "Car [date=" + date + "]";
    }
}

public class DateSort {

    public static void main(String[] args) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        List<Car> carList = new ArrayList<Car>();
        try {
            carList.add(new Car("car1",dateFormat.parse("2017-01-10")));
            carList.add(new Car("car1",dateFormat.parse("2017-02-10")));
            carList.add(new Car("car1",dateFormat.parse("2017-02-30")));
            carList.add(new Car("car1",dateFormat.parse("2017-01-09")));
        } catch (ParseException e) {
            System.out.println(e.getMessage());
        }
        /*
         * if you wish to change sorting order just 
         * replace -1 with 1 and 1 with -1
         * 
         * 
         * date1.before(date2)  returns true when date1 comes before date2 
         * in calendar
         * 
         * java docs :: https://docs.oracle.com/javase/8/docs/api/java/util/Date.html#before-java.util.Date-
         * */
        Collections.sort(carList, new Comparator<Car>() {
            @Override
            public int compare(Car o1, Car o2) {
                if(o1.getDate().before(o2.getDate())){
                    return -1;
                }
                return 1;
            }
        });
        System.out.println(carList);
    }

}
SmashCode
  • 741
  • 1
  • 8
  • 14
2

Can you try that. I think it will work:

SimpleDateFormat f = new SimpleDateFormat("YYYY-MM-DD HH:mm");
        Stream<Date> sorted = l.stream().map(a->{
            try {
                return f.parse(a);
            } catch (ParseException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return null;
        }).sorted();

UPDATE: and if you want a list:

List sorted = l.stream().map(a->{
            try {
                return f.parse(a);
            } catch (ParseException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return null;
        }).sorted().collect(Collectors.toList());

UPDATED: (as question updated using "cars")

SimpleDateFormat f = new SimpleDateFormat("YYYY-MM-DD HH:mm");
        List<Car> sorted = cars.stream().sorted(
                (a,b)->
        {
            try {
                return f.parse(a.getDate()).compareTo(f.parse(b.getDate()));
            } catch (ParseException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return 0;
        }
        ).collect(Collectors.toList());
strash
  • 1,291
  • 2
  • 15
  • 29
2

If you are using java 8:

 DateTimeFormatter fm = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
 objects.sort((o1, o2) -> LocalDateTime.parse(o1.getDateStr(), fm)
                    .compareTo(LocalDateTime.parse(o2.getDateStr(), fm)));

And java 7:

DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm");
Collections.sort(objects, new Comparator<YourObjectType>() {
            public int compare(YourObjectType o1, YourObjectType o2) {
                try {
                    return df.parse(o1.getDateStr()).compareTo(df.parse(o2.getDateStr()));
                } catch(ParseException pe) {
                    // handle the way you want...
                }
        }
    });
Nestor Sokil
  • 2,162
  • 12
  • 28
1

Clean solution without ParseException:

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
list.sort(Comparator.comparing(shop -> LocalDateTime.parse(shop.getDate(), formatter)));
ZhekaKozlov
  • 36,558
  • 20
  • 126
  • 155
  • It shows me an error: Exception in thread "main" java.time.format.DateTimeParseException: Text '2017-04-02' could not be parsed: Unable to obtain LocalDateTime from TemporalAccessor: {},ISO resolved to 2017-04-02 of type java.time.format.Parsed – stackish Apr 15 '17 at 14:13
  • so its better without the exception, but not without the exception handling :D – strash Apr 15 '17 at 14:23
  • 1
    @stackish I think, this is because some of your dates do not contain the time part (e.g. `2017-04-02` instead of `2017-04-02 12:00`). – ZhekaKozlov Apr 15 '17 at 14:24
  • I've change all my dates to format "YYYY-MM-DD" without hours and still give me exceptions – stackish Apr 15 '17 at 14:29
  • @stackish Use `"yyyy-MM-dd"`. `YYYY` and `DD` mean a bit different things. – ZhekaKozlov Apr 15 '17 at 14:31
-1

A revision of my solution. If you define the following comparator class...

class ShopDateComparator implements Comparator<Shop> {
  @Override
  public int compare(Shop shop1, Shop shop2) {
    return shop1.getDate().toLowerCase().compareTo(shop2.getDate().toLowerCase());
  }
}

...then all you need to do sort cars (which I’m assuming is a list of objects of type Shop) is:

Collections.sort(cars, new ShopDateComparator());
Joey deVilla
  • 8,403
  • 2
  • 29
  • 15
  • but I've a List cars , and inside it I've a date as string in format "YYYY-MM-DD" and i'd like to sort by this date – stackish Apr 15 '17 at 13:52
  • My answer was just a guide, and the solution specific to your code would be quite similar: `Collections.sort(cars, (Shop shop1, Shop shop2) -> shop1.date.toLowerCase().compareTo(shop2.date.toLowerCase()));` – Joey deVilla Apr 15 '17 at 13:57
  • It doesn't work, i've tried your solution – stackish Apr 15 '17 at 14:09
  • I’ve revised my answer — check it out and see if it works for you. – Joey deVilla Apr 15 '17 at 14:21
  • @JoeydeVilla The `.toLowerCase()` are actually not needed, because the strings don't contain any letters, only `0123456789:- ` according to the used date-time format. – Thomas Fritsch Apr 15 '17 at 14:37
  • You’re right — it’s not absolutely necessary, but I generally add `.toLowerCase()` in my string comparators as a safety measure against typos, mis-entered data, and the like. – Joey deVilla Apr 15 '17 at 14:44