-3

I am having an issue where I believe I have to combine several concepts that I am reading about, but I can't seem to figure out a way to combine them that makes sense, or what would be most efficient. Here is my situation:

I am working with microservices which is why this is so oddly specific. Essentially I am getting a list of Volume objects from another service. A volume object contains three fields, a String type, a String date(which actually represents time in the format "HH:mm", blame the data modelers for the naming conventions), and an int close.

What I am trying to do is to take this list of objects and sort by date(time), then create a new list of objects which will contain the same dates(times), but will have different field values based off of calculations I am doing. In order to sort by time, I believe I need to convert the time fields to Date objects and then compare those. I'm struggling how to iterate through the objects and compare the converted fields. Something that I feel like has put me on the right path is this: How to sort a List<Object> alphabetically using Object name field

But I can't seem to get that to work. Here's my code:

volumeResources.sort(volumeResources, new Comparator<VolumeResource>(){
        @Override
        public int compare(VolumeResource v1, VolumeResource v2) {
            SimpleDateFormat format = new SimpleDateFormat("HH:mm");
            try {
                Date d1 = format.parse(v1.getDate());
                Date d2 = format.parse(v2.getDate());
            } catch (ParseException e) {
                log.error("Error in parsing string to date. ", e);
            }
            return d1.compareTo(d2);
        }
    });

Now right off the bat, I know that this must be incorrect because I started comparing the VolumeResources v1 and v2, but instead tried to compare the dates at the end. In place of the return statement above, I have also tried the one below, but I don't think that will always work because it's not actually setting the formatted object to a Date object:

return format.parse(v1.getDate()).compareTo(format.parse(v2.getDate()));

So that's where I'm lost. This seems like a fairly simple need when described in pseudocode, but I can't seem to figure out how to make it work functionally. Bonus points if there's a way I can populate the other fields I need easily from this. Double bonus points for using lambdas or helping me make this efficient.

Thanks for any and all help everyone.

Crislips
  • 420
  • 1
  • 4
  • 13

2 Answers2

1

A date in Java must have year, month, day. But you don't have such values, you have only HH:mm (hours, minutes). Using dates is not appropriate here. (And calling these values "date" is also strange, I suggest to rename.)

Notice that well-formed HH:mm can be sorted alphabetically to order correctly. So all you need to do is ensure that the input times follow \d\d:\d\d pattern. If you get for example 9:15 then add a padding 0 at the left. Something like this:

volumeResources.sort(volumeResources, new Comparator<VolumeResource>() {
    @Override
    public int compare(VolumeResource v1, VolumeResource v2) {
        return sanitized(v1.getDate()).compareTo(sanitized(v2.getDate());
    }
});

The sanitized method is for you to implement accordingly. If the values are already in the correct format, of type String, then you can drop these calls and simplify to:

        return v1.getDate().compareTo(v2.getDate();

Using lambda:

volumeResources.sort(volumeResources, (v1, v2) -> sanitized(v1.getDate()).compareTo(sanitized(v2.getDate()));
janos
  • 120,954
  • 29
  • 226
  • 236
  • Thanks for the advice. The data conventions were not determined by me, and it's not really worth the battle with the data modelers. I know date is a poorly chosen name. I guess in this situation I could have used LocalDateTime instead, but what you have written is definitely cleaner. I have one more caveat, which was something I hadn't gotten to yet, but was going to look into once I had this figured out. Let's say that the time goes "23:30", "24:00", "24:30:", "01:00", "01:30", "02:00". This would signify passing midnight and would need to then come after. How can I account for this? – Crislips Jul 11 '17 at 21:02
  • As far as I know, that is the extent of the requirements for this. I tried to be as concise as I could in my original answer, but completely forgot to include that. But the times will need to stay as they are in the final return. – Crislips Jul 11 '17 at 21:12
  • @Crislips All important requirements should have been stated in the question. Ideally with example inputs and expected outputs, especially including tricky corner cases you need to handle. If you forgot to do that, it's too late to change after your received an answer. The correct way to use this site in this case is to ask a new question. And make sure to include all important details next time. – janos Jul 12 '17 at 04:49
  • It hadn't really occurred to me at the time of the original question. It's something I realized later on, but I honestly think it's something that needs to be changed in the way the data is passed to me from the other service. This is not so robust as is. – Crislips Jul 12 '17 at 14:41
1

If you are using Java 8 and above the sorting by time (which is represented as String) may look like this:

    volumeResources.sort(new Comparator<VolumeResource>() {
        @Override
        public int compare(VolumeResource v1, VolumeResource v2) {
            return v1.getDate().compareTo(v2.getDate());
        }
    });

Prior Java 8 it should look like:

    Collections.sort(volumeResources, new Comparator<VolumeResource>() {
        @Override
        public int compare(VolumeResource v1, VolumeResource v2) {
            return v1.getDate().compareTo(v2.getDate());
        }
    });

Using lambda:

    volumeResources.sort((v1, v2) -> v1.getDate().compareTo(v2.getDate()));

Assuming that volumeResources is a populated mutable List (not null) and all entries have date field populated properly with a well formed time (no spaces, tabs, or missing leading 0)

Explanation

According to your definition of date field it is naturally sortable as a string, you do not need to convert them into java Date class.

Your example has an issue by using Java 8 sort method defined in List interface in a manner how it used to be prior Java 8 by using utility class Collections - this is wrong, you do not need to supply collection as a first parameter.

Vladimir L.
  • 1,116
  • 14
  • 23
  • Thanks for the assistance with this. I mentioned to janos that I have one more caveat, which was something I hadn't gotten to yet, but was going to look into once I had this figured out. Let's say that the time goes "23:30", "24:00", "24:30:", "01:00", "01:30", "02:00". This would signify passing midnight and would need to then come after. How can I account for this? – Crislips Jul 11 '17 at 21:09
  • @Crislips can you supply an example of incorrectly defined time mixed with correctly defined time and your expectation where the entries with incorrect time should be placed in the sorted list? – Vladimir L. Jul 11 '17 at 21:13
  • If I understand you correctly here's what I mean. I need to view these times in order of occurrence, not just by number. So let's say I have a @Vladimir L situation where the time crosses midnight, and the times increase in order. I would need to have a list of objects that would be sorted like so: "23:30", "24:00", "24:30:", "01:00", "01:30", "02:00". But with the current code they would be sorted as: "01:00", "01:30", "02:00", "23:30", "24:00", "24:30:" – Crislips Jul 11 '17 at 21:18
  • @Crislips How do you decide on what is starting time to order from? What if the "01:30" record belongs to a day with "23:30" record and not to the next day and just by coincidence was entered after a record with "23:30"? I mean, imagine there is a sequence: "17:50", "01:30", "17:40", "20:30", "23:12", "01:31", "01:30" - how that should be sorted at the end? – Vladimir L. Jul 11 '17 at 21:20
  • So the numbers will always have the same interval between them. The "first number" is the starting time and the :"last number" will be the current time. The times will appear in an even distribution between the two. So it will be obvious if they are occurring over night because they will be increasing in a distinct pattern. – Crislips Jul 11 '17 at 21:28
  • @Crislips are the records already sorted by time? if yes, then why do you need to sort them by time again? your requirements are really confusing, I guess a good example of data close to real might help, you can share it via https://pastebin.com/ – Vladimir L. Jul 11 '17 at 21:31
  • So when passed to the front end, the order does not matter. But since I need to populate the fields of the objects at specific times, in the ascending order, it matters for me in the backend. The list may not always be given to me in order, so I need to make sure it's ordered before I work with it. So the pseudocode that I'm thinking will be: get list from other service --> sort by time --> populate new objects with null type and close, but ordered times into a new list --> update these objects with the close calculations I've made --> return the new list of objects – Crislips Jul 11 '17 at 21:41