Reputation: 115
The situation I have is that I currently have a LinkedList of 'Appointment' objects which have the following attributes:
'patient' 'date' 'type'
The only functionality required is to loop through this LinkedList and display each appointment in order of 'date'. So, each time a new Appointment is created (using a method called 'addAppointment' in the same class as the LinkedList of appointments), the method will sort the linked list using a Comparator.
However, I was wondering if this is bad practice and if there is a better way to do this? I never need to get the 'Appointment' object by its index and so would it be better practice to use a Priority Queue?
Upvotes: 3
Views: 441
Reputation: 338446
NavigableSet
The NavigableSet
, and its predecessor, SortedSet
, define a contract for a distinct (no duplicates allowed) collection of objects maintained in a certain order.
The TreeSet
class bundled with Java implements this interface. For concurrency, or for very large collections, use ConcurrentSkipListSet
.
You said:
'Appointment' objects which have the following attributes: 'patient' 'date' 'type'
record Appointment ( String patient , LocalDate date , String type ) {}
Define a Comparator
to control the sorting. We pass a method reference to access the member field by which we want to sort. In our example that is the LocalDate
field named date
.
Comparator < Appointment > comparator = Comparator.comparing( Appointment :: date );
Track our appointments. Specify the comparator to use automatically as elements added to this set.
NavigableSet < Appointment > appointments = new TreeSet <>( comparator );
Sample data.
appointments.addAll(
List.of(
new Appointment( "Alice" , LocalDate.of( 2025 , Month.APRIL , 23 ) , "trim" ) ,
new Appointment( "Bob" , LocalDate.of( 2025 , Month.JANUARY , 23 ) , "dye" ) ,
new Appointment( "Carol" , LocalDate.of( 2025 , Month.MARCH , 23 ) , "set" )
)
);
Add another element.
appointments.add(
new Appointment( "Davis" , LocalDate.of( 2025 , Month.FEBRUARY , 23 ) , "cut" )
);
See results.
System.out.println( "appointments = " + appointments );
appointments = [Appointment[patient=Bob, date=2025-01-23, type=dye], Appointment[patient=Davis, date=2025-02-23, type=cut], Appointment[patient=Carol, date=2025-03-23, type=set], Appointment[patient=Alice, date=2025-04-23, type=trim]]
Sure enough, the Appointment
objects are kept in sorted order, arranged by the date.
You might want a secondary sort, to order any multiple appointments for the same date.
Comparator < Appointment > comparator =
Comparator
.comparing( Appointment :: date )
.thenComparing( Appointment :: patient );
In Java 21+, we have sequenced collections, adding more interfaces to the Java Collections Framework. These interfaces include:
NavigableSet
, SortedSet
, TreeSet
, and ConcurrentSkipListSet
all extend/implement those two new interfaces.
SequencedCollection < Appointment > appointments = new TreeSet <>( comparator );
Upvotes: 1
Reputation: 2301
I would disagree with everyone here so far and say go ahead and use a simple ArrayList. Your main use case is just to loop through the list and display it in order, right? You can sort an array list by using the Collections.sort() method, which will sort any list of objects implementing Comparable. So just implement Comparable in your Appointment object (only need to provide a .compareTo() method...the API explains this well, or the Java Trail on Collections) and your sorting will then be painless and easy. My experience is this is better performing than an object like TreeSet or a LinkedList.
Now those would be better performing if you were always inserting into the middle of the list a lot, but you seem to mostly be reading this list from what you said, so go for the ArrayList.
Upvotes: 1
Reputation: 7326
Use a PriorityQueue
Write a compareTo
method for your Appoitnment
object that specifies the natural ordering according to date.
PriorityQueue<Appointment> schedule = new PriorityQueue<Appoitnment>();
Appointment a1 = new Appointment();
Appointment a2 = new Appointment();
schedule.add(a1);
schedule.add(a2);
// Iteratively removes the earliest appointment remaining in the schedule
while (schedule.peek != null) {
System.out.println(schedule.poll().toString());
}
Upvotes: -1
Reputation: 77177
Generally speaking, use an ArrayList
when you need random access and a LinkedList
when there will be lots of inserts and removes. If you need a data structure that stays sorted, PriorityQueue
is an option, but it's really intended for the scenario where you're just pulling the top element off sequentially. If you're needing to repeatedly iterate over the elements, use a SortedSet
.
If a field involved in the element's ordering changes after it's inserted into any sorted collection, you should remove and re-add the element (preferably removing before modification).
Upvotes: 0