Java Collection sort - java

I am trying to sort a list of Dates and it's not working.
Here is the declaration and get function in AttEnt
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "end_time")
private Date endTime;
public Date getEndTime() {
return endTime;
}
Here is the sorting code that isn't doing anything. GetAttempts() gets the list of all the attempts for called. They aren't in order, and I just want to be able to get whatever attempt has the latest endTime.
List<AttEnt> attempts = called.getAttempts();
Collections.sort(attempts, new Comparator<AttEnt>() {
#Override
public int compare(AttEnt a1, AttEnt a2) {
if (a1.getEndTime() == null || a2.getEndTime() == null)
return 0;
return a1.getEndTime().compareTo(a2.getEndTime());
}
});
I believe that the code above should sort attempts, and then after it attempts should be sorted, so the latest end time would be attempts.get(attempts.size()-1).getEndTime()

Comparator<AttEnt> comparator = Comparator.comparing(AttEnt::getEndTime).reversed();
attempts.sort(comparator);
Java static methods in interfaces are your friend
Click HERE for more awesomeness

Related

Why does Collections not sorting objects properly using timestamp?

When I have fetched objects from firebase realtime database into ArrayList then they are not sorted properly using Collections.sort() method. I have total 17 objects(posts) in my fetched ArrayList in which 2 objects are 1 month ago and rest 15 are under a month. Collection sorts properly these 15 objects but these 2 objects are added before 15 objects in sorting.
I am sorting these objects into ascending order of timestamp to show newer posts first and older at last. But very old posts (more than 1 month) are added before on sorting.
I have following PostModel class structure for Firebase
PostModel Class:
public class PostModel {
public String title,description;
public long timestamp;
public PostModel(){}
public PostModel(String title, String description,long timestamp) {
this.title = title;
this.description = description;
this.timestamp = timestamp;
}
}
I have passed timestamp into above class objects for insertion as System.currentTimeMillis(); and sorted using following way.
Collections.sort(postsObjs, new Comparator<PostModel>() {
#Override
public int compare(PostModel o1, PostModel o2) {
return (int) (o2.timestamp - o1.timestamp);
}
});
Help me to sort my objects properly. Thanks
Edit: I have 17 objects in my ArrayList instead of 7 and rest is same
A compare method should return -1,0 or 1;
0: if (x==y)
-1: if (x < y)
1: if (x > y)
try this:
return Long.compare(o2.timestamp - o1.timestamp);

How to generate objects with complex condition in a functional manner?

I want to create a list of Java objects based on some conditions. I want to do this using functional programming principles.
I took a look at Stream.generate() with .limit() but I can't add a predicate to limit to stop with a condition. Plus I don't know how to pass the modified start OffSetDateTime to the new object to be created.
public class Test {
private String name;
private OffsetDateTime timestamp;
}
public List<Test> generateTestObjects(OffsetDateTime startTime) {
ArrayList<Test> tests = new ArrayList<>();
for(OffsetDateTime start = startTime; start.isBefore(startTime.plusMinutes(100)); start = start.plusMinutes(1)) {
tests.add(new Test(start));
}
return tests;
}
With Java 9, you can use the three-argument Stream#iterate with the condition that you already have in your for-loop:
public Stream<OffsetDateTime> generateTestObjects(OffsetDateTime startTime) {
return Stream.iterate(startTime, time -> time.isBefore(startTime.plusMinutes(100)),
time -> time.plusMinutes(1));
}
If you want to return a List, you can add .collect(Collectors.toList()):
public List<OffsetDateTime> generateTestObjects(OffsetDateTime startTime) {
return Stream.iterate(startTime, time -> time.isBefore(startTime.plusMinutes(100)),
time -> time.plusMinutes(1)).collect(Collectors.toList());
}
Note that I excluded your mapping to Test, which would be equivalent to adding .map(Test::new) before calling collect.

How to write code simply using stream api

I have the following classes:
#Getter
public class SomeClass implements Serializable {
private LocalDate date;
private String smth;
List<PairKeyValue> quotaParams;
}
The class PairKeyValue is just:
#Getter
public class PairKeyValue implements Serializable {
private String key;
private String value;
}
I want to do the following:
1) Check if in SomeClass's date equals sysdate then check value under key="somekey" in list<PairKeyValue> is equals to 1 (somekey = 1) then left it in list.
2) Check if in SomeClass's date NOT equals sysdate then check value under key="somekey" in List<PairKeyValue> is equals to 0 (somekey = 0) then left it in list.
3) And ignore other values.
So in the end I need a filtered list of only current values within SomeClass.
I have my realization but I don't like it is not using only stream API:
availableQuotes = ArrayList();
if (CollectionUtils.isNotEmpty(availableQuotes)) {
availableQuotes = availableQuotes
.stream()
.filter(this::checkDate).collect(toList());
}
private boolean checkDate (SomeClass someClass){
if (someClass.getDate().equals(LocalDate.now())) {
return checkDuration(someClass, "0");
} else {
return checkDuration(someClass, "1");
}
}
private boolean checkDuration (SomeClass someClass, String param){
List<PairKeyValue> quotaParams = someClass.getPairKeyValues().stream()
.filter(spKeyValue -> spKeyValue.getKey().equals("duration"))
.filter(spKeyValue -> spKeyValue.getValue().equals(param))
.collect(toList());
return (CollectionUtils.isNotEmpty(quotaParams));
}
I know it looks awful and I know it can be more readable so please help.
If I understood your question right, the last 2 functions can be resumed to the following:
availableQuotes = availableQuotes.stream()
.filter(availableQuote -> availableQuote.getQuotaParams().stream()
.anyMatch(quotaParam -> quotaParam.getKey().equals("duration")
&& quotaParam.getValue().equals(availableQuote.getDate().equals(LocalDate.now()) ? "0" : "1")))
.collect(Collectors.toList());
I mostly took your code and re-arranged it into a single filter.

Correct implementation of time based storage of objects

For a given task, I should store an object while keeping track of the time of its creation at least per day.
The easiest solution I could find is to use Calendar to set day of year based on time stamp of objects creation.
Here is the object in a simple form:
public class PhysicalActivity implements Serializable {
private long mTimestamp;
private int mYear;
private int mMonthOfYear;
private int mWeekOfYear;
private int mWeekOfMonth;
private int mDayOfYear;
private int mDayOfMonth;
private int mDayOfWeek;
public PhysicalActivity(long timestamp){
mTimestamp = timestamp;
Calendar c = Calendar.getInstance();
c.setTimeInMillis(mTimestamp);
c.setTimeZone(TimeZone.getDefault());
mYear = c.get(Calendar.YEAR);
mMonthOfYear = c.get(Calendar.MONTH);
mWeekOfYear = c.get(Calendar.WEEK_OF_YEAR);
mWeekOfMonth = c.get(Calendar.WEEK_OF_MONTH);
mDayOfYear = c.get(Calendar.DAY_OF_YEAR);
mDayOfMonth = c.get(Calendar.DAY_OF_MONTH);
mDayOfWeek = c.get(Calendar.DAY_OF_WEEK);
}
//Getters for all members...
}
Then I have this object that holds all instances in an List<PhysicalActivity>:
public class PhysicalActivityHolder implements Serializable {
private long mCreationTimestamp;
private long mLastUpdateTimestamp;
private List<PhysicalActivity> mList;
public PhysicalActivityHolder(long creationTimestamp) {
mCreationTimestamp = creationTimestamp;
if(mList == null) {
mList = new ArrayList<PhysicalActivity>();
}
}
public void addPhysicalActivity(PhysicalActivity pa){
if(mList == null) {
throw new NullPointerException("List is null");
} else {
mList.add(pa);
}
}
public List<PhysicalActivity> getPhysicalActivitiesForDayOfYear(int dayOfYear) {
List<PhysicalActivity> activities = null;
for(PhysicalActivity p : mList) {
if(p.getDayOfYear() == dayOfYear){
activities.add(p);
}
}
return activities;
}
//Some similar methods for getting list by month of year, week of year...etc...
}
Then whenever there is a new PhysicalActivity instance is coming, I read the PhysicalACtivityHolder from disk (deserialize), add the new instance to the List<> and then save (serialize) the Holder object again to the disk.
I hope that you got my point by now. I am afraid this is not going to be a good solution. one of the problems is what if the device's timestamps changes? then the whole idea will be ruined.
I would love to know how would you implement such task? what could be the better way of doing this?
First of all, while not related to the timestamp issue, an SQLite Database would seem like a much more appropriate medium to store this information. In particular:
You don't need to serialize and deserialize the whole collection every time.
You don't need to keep the whole collection in memory.
You can add, remove, or update single events.
You can easily query by year, month, &c using SQL SELECT statements.
About the "timestamp changing" part (unless you have an external, trusted data source for the time, such as a server), yes, the device's date or time may be manually changed. However, how big of a problem would that be? This data wouldn't seem to be critically dependent on having the exact time.

Problem with Priority Queue

I'm trying to use a priority queue in my code, and for some reason when I remove the objects, they aren't in order. Do you know what i"m doing wrong?
Here's my code:
the contructor:
recordedsong = new PriorityQueue<recordedNote>(50, new Comparator<recordedNote>()
{
public int compare(recordedNote n1, recordedNote n2)
{
long l = n1.rt()-n2.rt();
int i = (int)l;
return i;
}
});
where each recordedNotehas a long value that is returned my the method rt().
But when I call
while (!Song.isEmpty())
{
recordedNote temp = (recordedNote)Song.remove();
and then print temp.rt() for each one, all the numbers are out of order. And not just like reverse order, but all over the place, like 1103, 0, 500, 0, 220 orders like that.
Can you see if there's anything wrong with my contructor?
Thanks!
remove should work, and in fact it does work fine in a small example program that I created to help answer this question:
import java.util.Comparator;
import java.util.PriorityQueue;
public class TestPriorityQueue {
public static void main(String[] args) {
long[] noteTimes = {1103L, 0L, 500L, 0L, 220L, 1021212812012L};
PriorityQueue<RecordedNote> noteQueue = new PriorityQueue<RecordedNote>(10,
new Comparator<RecordedNote>() {
#Override
public int compare(RecordedNote o1, RecordedNote o2) {
Long time1 = o1.getTime();
Long time2 = o2.getTime();
// uses Long's built in compareTo method, so we
//don't have to worry as much about edge cases.
return time1.compareTo(time2);
}
});
for (int i = 0; i < noteTimes.length; i++) {
RecordedNote note = new RecordedNote(noteTimes[i]);
System.out.println(note);
noteQueue.add(note);
}
System.out.println();
while (noteQueue.size() > 0) {
System.out.println(noteQueue.remove());
}
}
}
class RecordedNote {
private long time;
public RecordedNote(long time) {
this.time = time;
}
public long getTime() {
return time;
}
#Override
public String toString() {
return "[Time: " + time + "]";
}
}
So this begs the question, why isn't it working for you? Myself, I don't see enough coherent code in your question to be able to answer this. We're not sure what is Song as I don't see this declared as a class or a variable, and I also don't see where you're using your PriorityQueue variable, recordedsong, anywhere. So I suggest you do the same thing as I: create a small compilable runnable program that we can run and modify and that demonstrates your problem, an http://sscce.org
I guess there is a possibility for i getting 0. So modify compare method so that it returns a positive value rather than the result.
Reading the API docs for PriorityQueue, it states the following:
The Iterator provided in method iterator() is not guaranteed to traverse the elements of the priority queue in any particular order. If you need ordered traversal, consider using Arrays.sort(pq.toArray()).
My guess is that remove() is not obligated to follow the natural ordering, either.

Categories

Resources