Well , I'm stock on something very simple but I can't figure it out.
First off, I know that there is Collection.sort() method, but my ArrayList is sort of links to data to main object, and my sorting is needed to be made according to this object's data.
Like this is a sport competition and ArrayList<Integer> numbers is keeping numbers of participants that has passed a checkpoint.
And I need to sort this ArrayList by the best time from min to max to set them on who's on 1st place, 2nd etc.
for this I should ask my Competiton object :
public ArrayList<Integer> sort (ArrayList<Integer> numbers)
for (int i=0;i<numbers.size){
long time = competition.participant.get(numbers.get(i)).getTimeOfLastCheckPoint();
/*Do something to make another ArrayList<Integer> sortedArray
where all this will be sorted by this time parameter from minimal to maximum*/
return sortedArray;
}
this is not the actual code, but you've got the idea. I stuck with trying to find seemingly easy solution.
Please Help
It seems awkward to sort an ArrayList<Integer> based on other things that have nothing directly to do with what you actually want to sort on -- the times.
I would design it differently. It looks you have some kind of object defined on which you can call getTimeOfLastCheckPoint(). For now, I'm assuming it's called Participant. Instead of maintaining an ArrayList<Integer> to store index-based references to your participants, I would maintain an ArrayList<Participant>.
Then I would create a class that implements Comparator<Participant> (perhaps ParticipantComparator) (Comparator javadocs) that knows how to compare Participants based on the results of the call to getTimeOfLastCheckPoint(). Then sorting is simply Collections.sort(participantsArrayList, new ParticipantComparator());.
Write a java.util.Comparator that compares Integers by using them as index in your participants-array:
public class ParticipantIndexComparator implements Comparator<Integer> {
final List<Participant> participants;
public ParticipantIndexComparator(List<Participant> participants) {
this.participants = participants;
}
#Override
public int compare(Integer i1, Integer i2) {
long l1 = participants.get(i1).getTimeOfLastCheckPoint();
long l2 = participants.get(i2).getTimeOfLastCheckPoint();
return Long.compare(l1, l2);
}
}
Now you can use this comparator to sort your integers:
Collections.sort(numbers, new ParticipantIndexComparator(participants));
But before doing so, ask yourself why your list contains Integer-objects that are indices to the participants-list, instead of the Participants themselves!
For me, this sounds like a workaround solution for a half-done SQL query. In case that your data resides in a data base (and I'm pretty sure that this is the case), modify your SQL- query so that you don't have to do that sorting of data at application level. This is good for at least two reasons:
Simplyfiy application logic
Speed up execution (The data base can do such sorting much faster)
You can use a Comparator to sort the list according to their race duration and also use for-each loop in Java.
Related
Which Java Collection should I use if I have a lot of Objects with slowly changing keys?
Basically I have one ArrayList that has all the Objects that need sorting. That ArrayList is changed by an other Thread sometimes. To iterate over it I have written the ArrayList to another ArrayList with clear and then addAll until now, but I now realized that can also cause the ConcurrentModificationException, so I want to change that.
That new Collection (currently ArrayList) that I use for iteration needs to be sorted with a custom Comparator. The problem is that, before I make the next copy of the original, the keys will change and I will have to sort it multiple times. The order for these sorts is almost correct already usually. An insertion sort may be good here.
The big question now is:
Do I use TreeSet and call Collections.sort on it when the order changed
Do I use some kind of List (which kind? ArrayList? LinkedList?) and call Collections.sort when order changed
I think the correct answer for this question can only be given when considering that I have to copy an other unsorted Collection first (ArrayList, but not necessarily) and do that while the Data in the Collection is changed by an other Thread.
My thoughts on the solution are following:
Have the second Collection be a ArrayList and update it always with Collections.copy (making it the right size first, but it should usually be the right size already in my scenario (I realize this is not atomic and can cause issues)), then call Collections.sort on it as often as I want. Maybe implement insertion sort algorithm for every sort after the initial sort, because it should be faster then.
Use TreeSet for the second collection somehow. The problem is I don't know how I would iterate over the original threadsafe to add all the elements from there. Also I don't know how to sort the Set after that initialization efficiently. I saw someone use Collections.sort, but I don't know about efficiency there. Also remember it is almost sorted.
What you need to also keep in mind, I only need iterating over both, the original and the working copy Collection, no indexing is necessary.
I have made some Java Code to show the Problem now:
public static List<FloatWrapper> pending_additions = Collections.synchronizedList(new ArrayList<>());
public static List<FloatWrapper> pending_removals = Collections.synchronizedList(new ArrayList<>());
public static List<FloatWrapper> list = new ArrayList<>();
public static Random rnd = new Random();
public static void main(String[] args) {
// initialize array
for (int i = 0; i < 1000; i++) {
list.add(new FloatWrapper(i));
}
// the main loop (runs basically infinitly)
for (int runs_infinitly = 0; runs_infinitly < 100; runs_infinitly++) {
// apply pending changes
synchronized (pending_additions) {
list.addAll(pending_additions);
pending_additions.clear();
}
synchronized (pending_removals) {
list.removeAll(pending_removals);
pending_removals.clear();
}
// doing my stuff
for (int i = 0; i < 5; i++) {
// sort array with quicksort I believe, which is not the fastest
// for this scenario usually, except for the start when its completly unsorted
System.out.println("sorting");
Collections.sort(list);
// iterate very often doing different things
for (int j = 0; j < 1; j++) {
for (FloatWrapper num : list) {
// do something with num
System.out.print(num.number + " ");
}
System.out.println();
}
System.out.println("changing keys");
// change the values that are used for sorting
for (FloatWrapper num : list) {
num.number += (rnd.nextFloat() - 0.5f) * 0.2f;
}
}
}
}
public static class FloatWrapper implements Comparable<FloatWrapper> {
public float number;
public FloatWrapper(float number) {
this.number = number;
}
public int compareTo(FloatWrapper arg0) {
return Float.compare(number, arg0.number);
}
}
The Arrays pending_additions and pending_removals are the only ones written from an other Thread. They are my improvement since I wrote this post, so not the whole List needs to be copied and resorted.
My Question still stands, should I use a TreeSet to increase performance, should I do something else different? Basically I don't know about sorting a TreeSet efficiently. I could even imagine that the ArrayList with Collection.sort() is more efficient, but I don't know. Can someone explain that.
Also I'm using a custom Comparator which has even a little bit of maths in it so it is really benificial to optimize the process of sorting here
Your current implementation already leverages that the list is partially sorted:
The Javadoc for Collections.sort writes
This implementation defers to the List.sort(Comparator) method
and the Javadoc of that method says
This implementation is a stable, adaptive, iterative mergesort that requires far fewer than n lg(n) comparisons when the input array is partially sorted, while offering the performance of a traditional mergesort when the input array is randomly ordered. If the input array is nearly sorted, the implementation requires approximately n comparisons. Temporary storage requirements vary from a small constant for nearly sorted input arrays to n/2 object references for randomly ordered input arrays.
The implementation takes equal advantage of ascending and descending order in its input array, and can take advantage of ascending and descending order in different parts of the same input array. It is well-suited to merging two or more sorted arrays: simply concatenate the arrays and sort the resulting array.
The implementation was adapted from Tim Peters's list sort for Python ( TimSort). It uses techniques from Peter McIlroy's "Optimistic Sorting and Information Theoretic Complexity", in Proceedings of the Fourth Annual ACM-SIAM Symposium on Discrete Algorithms, pp 467-474, January 1993.
Since you are iterating over the collection far more often than sorting it, the iterations (and the actions therein) are likely far more costly than the sort. That is, you are unlikely to get a significant improvement by further tuning the sort.
What you really need is not exactly clear, but I think you should be fine with maintaining a CopyOnWriteArrayList<T>, which you then iterate with
list.stream().sorted(yourComparator).forEach(yourAction);
The CopyOnWriteArrayList is thread-safe, ie if some other thread changes it while the iteration is going, you won't get a ConcurrentModificationException and continue iterating the list as it was when you started.
EDIT: Or, since you want to iterate several times:
List<FloatWrapper> sorted = list.stream().sorted().collect(toList());
for (int i = 0; i < 5; i++) { sorted.forEach(i -> doYourStuff(i)); }
I currently have 3 arrays of information and am unsure of how to sort them based on one of the values:
int[] rank = { 1, 3, 4, 2, 5 };
String[] game = { "Snake", "Mines", "Fragged", "Siege", "Tower" };
int[] year = { 1980, 1983, 1981, 1995, 1992 };
I'm wanting to sort it by rank, and I've seen many examples of people using comparators to sort 2 parallel arrays, but I haven't seen any example for sorting more than 2.
My first thought was to create a class with a variable for each and then sort that object, but is an extra class really necessary for a sort?
My first thought was to create a class with a variable for each and then sort that object, but is an extra class really necessary for a sort?
It's not strictly necessary - you could definitely write some code to avoid it if you really wanted to. However, I'd say it's a thoroughly good thing.
You don't really have three collections of separate items here: you have one collection of items, each of which has three properties. So make your code match that. Whenever you find you have parallel collections, such that a[0] is related to b[0] is related to c[0] etc, you should think about encapsulating that information in a separate class. It will make your code much easier to maintain, and enforces more consistency.
For example, it would make no sense for those arrays to have different lengths: but there's nothing inherent in the declaration to stop that. If you have one collection, you can't possibly have different numbers of items for the different properties, precisely because you've got one collection.
I think creating a new class would be the cleanest solution. You could manually implement a new sort function to duplicate swaps to the other 2 arrays whenever you apply a swap to the first array (rank), but that gets messy very quickly.
Something like the following would be all you need:
public class Game implements Comparable<Game>{
private int rank = 0;
private int year = 0;
private String name = "";
...
// Constructor +
// Usual getters and setters here
..
public int compareTo(Game anotherGame) {
return this.rank - anotherGame.getRank();
}
}
And then you can simply do:
List<Game> games = new ArrayList<Game>();
...
// Add some games to your games list
...
Collections.sort(games);
Is the extra class necessary? Well no, of course not. You could come up with a sorting routine that would keep everything consistent. However, what happens if next week you decide you need a 4th array, such as a publisher? Now your sorting routine won't work and you have to write a new one.
If you instead write a class to hold these fields as properties, you can simplify the sorting logic immensely, plus you only have to worry about one array. Any extra work you do now will be recouped very quickly then next time you have to maintain this code.
I wanted to know what changes should I be making to this code to reduce its execution time.
import java.util.*;
public class ExamPeekableQueueImpl <E extends Comparable<E>> implements ExamPeekableQueue<E> {
LinkedList<E> li = new LinkedList<E>();
public ExamPeekableQueueImpl(){
}
public void enqueue(E e){
if(li.isEmpty()){
li.add(0, e);
}
else
li.add(e);
}
public E dequeue(){
li.pollFirst();
return null;
}
public void printlist(){
System.out.println(li.toString());
}
public E peekMedian(){
int var = (((li.size())/2)+1);
Collections.sort(li);
//Integer var2 = li.get(var);
System.out.println("the median is:" + li.get(var-1));
return null;
}
public E peekMaximum(){
Collections.sort(li);
System.out.println("the maximum is:" + li.getLast());
return null;
}
public E peekMinimum(){
Collections.sort(li);
System.out.println("the minimum is:" + li.getFirst());
return null;
}
public int size(){
li.size();
return 0;
}
}
Also I wanted to know is whether for implementing queues, LinkedList is faster or ArrayList or any other data structure.
This is a loaded question.
What operation do you want to speed up? Right now, your peekMin/Max/Mid code is quite slow because you have to sort each time. However, your insert code is fast. If you want, you can maintain a sorted data structure internally. This would slow down your insert method, but speed up your peek methods. There is often a tradeoff of speed between operations like this. It's rare to be able to just speed up ALL the operations on some data structure, so you need to pick what operations you think are common, and optimize those.
It's about what operations you want to speed up.
Currently you have O(1) for insertion and O(nlogn) for getMin/getMax/getMedian. You can move the logn from the getters to the insertion part by using a sorted data structure. Or you can leave the insertion as it is and optimize getMin/getMax by doing a linear search through the list and just storing the minimal value. For getMedian there is nothing to do as you need a sorted set for that.
A further optimization would be to store the min/max and update the two values during each insertion step. This will not have any (non-constant) change on insertion and will reduce your getMin/getMax to O(1). (thanks to Tedil)
The same applies for getMedian, where you would keep a sorted list in parallel to your linked list. You can then simply pick the median out of the middle of that list. Of course this will change insertion time to O(logn) or worse (depending on the list you use) and will also double the amount of storage space. So it is a more expensive optimization than the one for getMin/getMax.
To answer your latter question. please take a look at this topic to learn about the differences between using arrays or linked list in structures.
Also, as an advice, when declaring structures, always use the interface as the type so that you can change the implementation without affecting the functionality.
It depends.
Actually, one thing most people answering/commenting don't realize is that Collections.sort gives about N performance on a nearly sorted list. (N log N is the performance if the list is not at all sorted.)
As others, have said, maybe you should be sorting when you change the list rather than read the list. Maybe you should be using an Ordered Set rather than list. (If you really need a list to hold multiple copies of an item, consider using a Ordered Map and making the number of occurrences the value.)
You can also consider making a an object that stores the Collection and keeps track of the min and max without sorting it. This would work well if finding medians is rare or if you can get away from needing the median.
In the peekMaximum() and peekMinimum() methods, instead of sorting the LinkedList you can directly use the methods Collections.max(li) and Collections.min(li).
I think that will save the time wasted to sort the list.
class Collection
{
int sNo;
String sessionID;
int noOfDependency;
int noOfRejection;
int totalValue;
Collection(int sNo, String sessionID, int noOfDependency, int noOfRejection, int totalValue)
{
this.sNo = sNo;
this.sessionID = sessionID;
this.noOfDependency = noOfDependency;
this.noOfRejection = noOfRejection;
this.totalValue = totalValue;
}
}
public class DependencyStack {
/** Creates a new instance of DependencyStack */
public DependencyStack()
{
LinkedList lList = new LinkedList();
lList.add(new Collection(1,"a",0,0,0);
lList.add(new Collection(2,"b",0,0,0));
for(int i=0;i<lList.size();i++);
System.out.println(lList.getFirst());
}
I am not able to view the individual data. For e.g. if i want to view all sno "serial nos.", how can i do that.. i have tried lot of options, please helpp...
Use the standard API library as God, um, I mean Gosling intended.
Seriously, those have been tweaked, optimized and bugfixed a hundred times over - you're very unlikely to do any better.
In fact, java.util.LinkedList already has a size counter. But ArrayList is better for most cases (exception: if you often need to remove elements while traversing).
BTW, 500-1000 elements is chump change. It's nothing. You've wasted more time asking this question than your program would running an O(n) implementation a million times.
Edit: To store more than one piece of data in one node or list slot, write a class that has your data as fields (private and exposed via set and get methods if you want it to be particularly "clean") and put instances of that class into the list.
Is there a reason you don't want to use a built in class, like List?
these classes take care of all the implementation details for you. look at java.util.List
Java's LinkedList class keeps track of the size as you add/remove elements. Getting the size is free, you don't traverse the list. Don't worry about multiple pieces of info in a node, just put all you info in an object.
I know this is homework, but you really shouldn't seem so demanding and consider posting some code that illustrates you problem. We're not doing you work for you.
System.out.println(lList.getFirst());
lList.getFirst() returns an object of type Collection (you should use a better name BTW).
So you have to access to lList.getFirst().getSerialNumber() for example (and you also will have to write the method getSerialNumber() in your Collection class...
I'm new to java so im having some "annoying" problems. I have a class Employee which contains an int idNumber and a int phone number. Then I have a LinkedList<Employee> sorted by idNumber. I want to change the phonenumber of a certain idnumber.
I've been working with Iterators but i don't know if i'm doing it right, which I doubt.
public void setNewPhoneNumber(int idnumber, int newphone){
Iterator<IndexC> it = listEmployee.iterator();
IndexC employeeTemp = null;
boolean found = false;
while(it.hasNext() && !found){
employeeTemp = it.next();
if(employee.getIdNumber()== idnumber){
employeeTemp.setNewPhoneNumber(newphone);
found = true;
}
}
}
Yeah, I know employee.setNewPhoneNumber is wrong, but I don't know which the correct way change the value on the linkedlist. (Sorry for the bad english, not a native speaker)
Iterators are a pain; the foreach construct is a lot nicer:
public void setNewPhoneNumber(int idnumber, int newphone) {
for (Employee employee : listEmployee)
if (employee.getIdNumber() == idnumber) {
employee.setNewPhoneNumber(newphone);
return;
}
}
I'm not clear on what IndexC is, and I don't often use LinkedList - there could be some subtlety here I'm missing - but I think you're better off avoiding the iterators.
You're not "changing parameters in a Linked List", you're trying to find an object in a list and change a property of that object
You should be using a Map (such as a
HashMap) instead of a List, then you
won't have to iterate.
If you iterate, use the for loop: for(IndexC employeeTemp: employeeTemp){}
Changing the phone numer would conventionally be done through a setPhoneNubmer() method, but it depends entirely on the IndexC class whether it has such a method. Look at that class's definition.
When asking a question, always include error messages! "It doesn't work" is a really useless piece of information.
my bad, IndexC is the Employee class, "bad copy past" sorry. I don't like LinkedList but i have to use it with +5000 entries (School Exercise). I don't think using for's with so many entries is recommended.
The class as set's, get's, clones..
class Manager{
private LinkedList<Employee> listE = new LinkedList<Emploee>;
public void setNewPhoneNumber(int idnumber, int newphone)
}
One reason for it not to work is that there´s no IndexC in the list that satisfies (employee.getIdNumber()== idnumber).
Maybe you should post some extra code, for example, where is that list created, have you filled it with anything?
Besides, what is it that doesn´t work? The setting of the new phone number, or retrieving the element from the list?
In both cases, i think that you should post both methods, that is
getIdNumber();
As Mike B. says, maybe using a Map implementation would be better. Since you are considering order, maybe a SortedMap (such as TreeMap) implementation could be better.
In any case, rember you have to override two methods in your IndexC (when using maps). Otherwise, things will get messy.
equals
hashCode
http://java.sun.com/j2se/1.4.2/docs/api/java/util/LinkedList.html
You want to use a for loop with an int incrementing till you find the object you want. Then you want to use listEmployee.get() to get the object you want and edit it.
However, if you need random access to items like that, then you should not be using Linkedlists. Stick it in an ArrayList instead. That has much better random access time.
As a side note, you don't even need the for loop if the id numbers are in order from 0-whatever. You can simply listEmployee.get(idNumber)