I had to write a merge sort function in Java. No problem. Well, a little, but I got through it. Then the follow up question I didn't get.
Question: Given an array A[][] such that A[i][0] is a float and A[i][1] is a nonnegative int giving the multiplicity of the value A[i][0] (here think of a big vector that's been collapsed down by combining repeated entries and recording how many got combined), write a version of merge sort that returns B[][] where B[i][0] < B[i+1][0] for all i.
Any ideas? The best I could do was merge sort and then group the equal ones, but apparently you can do it all in one step.
Strage question... and using different types in these arrays is just ugly (personal point of view).
However, the most useful thing to do, is to rewrite your merge function with a Comparator.
This way you can sort using whatever property you want.
You would end up with a signature like void merge(A[] arr, Comparator<? super A> comp).
By the way, the Java implementation of sort is a lot like this.
To solve your question you would call:
A[][] a = ...;
merge(a, new Comparator<A[]>() {
int compare(A[] a, A[] b) {
return ((Float)a[0]) - ((Float)b[0]);
}
});
Related
I've been looking around on the internet trying to find out how to sort a multidimensional array by column and i found a way that works but I'm not sure exactly how it works. Can someone explain it to me?
Arrays.sort(data, (int[] num1, int[] num2) ->
Integer number1 = num1[1];
Integer number2 = num2[1];
return number2.compareTo(number1);
});
in this care the code sorts the array [][] in descending order by the second column.
A two dimensional array is an array whose elements are arrays (int[] in your case). Therefore, in order to sort such an array, you should supply a comparator that compares int[] objects. This is exactly what the lambda expression in your code snippet does. It accepts two int[] objects and determines their relative order by comparing the elements at the second position (i.e. index 1) of the two arrays.
The lambda expression is a feature added in Java 8. It allows you to supply an implementation to a functional interface (which is an interface with a single method, such as Comparator<int[]>, whose single method is int compare (int[] first, int[] second)) without most of the syntax required for anonymous class instances.
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.
Let's say we have a function with the following prototype:
public static funWithMatrices(int[][] aux)
Now, we could do:
int i = aux.length;
To get the number of rows in aux. Similarly, we could then do:
int j = aux[i].length;
To just get the length of each column. But is there a better way to do this? Of course, the compiler can't possible know that what you're passing is a matrix rather than an arbitrary array with differing row/column lengths, but is it possible to constrain it somehow?
I'd be more interested in something that's already built-in rather than creating my own matrix object with the given constraints. Though that'd be easy to do, it's not quite what I'm asking.
Sneak edit: I realize there is also the possibility of redefining the prototype to something like int[][] aux, n, m, but that is also not quite what I'm asking.
You can leverage object oriented programming nature of Java and create your own Matrix class with getColumnLength() and getRowLength() methods defined, or even better have a look at Apache Commons Math libraries and leverage existing Matrix API classes and functions
There is also la4j library that can be used as following:
public static void funWithMatrices(Matrix aux) {
int rows = aux.rows();
int columns = aux.columns();
// do what you want with matrix
// for example multyply each cell by 2 if it's symmetric matrix
if (aux.is(Matrices.SYMMETRIC_MATRIX)) {
Matrix aux2 = aux.transform(Matrices.asMulFunction(2.0));
}
}
// a caller
funWithMatrices(new Basic2DMatrix(new double[][]{
{ 1.0, 2.0 },
{ 3.0, 4.0 }
}));
which is the best way to write a bidimensional hashmap efficiently in Java? Just to give an example of what I'm talking about: I'm developing some algorithms related to collective intelligence, these algorithms works by calculating correlation between pairs of elements..
Without caching these values, since they are calculated on same pairs multiple times, performance are horrible.. (algorithms can be O(n^2) but maybe O(n^3) so I was thinking about using an HashMap to store values to be used multiple times.
Which is the most efficient way to implement such a data structure in Java? It should be possble to cache and remove a value generated by a pair of elements with O(1), but using an explicit class seems too heavy anyway.
If Java will turn out to be not enough I'll have to switch to C/C++, so any idea related to these languages are welcome too.
Thanks
The easiest way to do this is to define a Pair class. It should be immutable (hash keys should not change), and hashCode() should be consistent with equals.
Something like (method implementations omitted):
public class Pair() {
int a, b;
public Pair(int a, int b);
public int getA();
public int getB();
public boolean equals(Object obj);
public int hashCode();
}
Notes:
If you don't want ints, sub in whatever type you want, or make your Pair class generic if you want it to be flexible.
It would be up to you whether (x, y) == (y,x).
With this in hand, you can have a HashMap<Pair, SomethingElse> as your cache.
I partially solved the problem by concatenating hashcodes of both items using something like this:
private long computeKey(Object o1, Object o2)
{
int h1 = o1.hashCode();
int h2 = o2.hashCode();
if (h1 < h2)
{
int swap = h1;
h1 = h2;
h2 = swap;
}
return ((long)h1) << 32 | h2;
}
I still have to figure out which is the most efficient way to store all the elements already cached with a specified one to remove them when the algorithm don't need the item anymore, just to avoid filling of the HashMap with a waste of item. That's because the kind of algorithm merges two items at every iteration removing them from used ones but adding the new generated item.
Google Collections supports bi-directional hashmaps, see BiMap.
(BTW, Google Collections seems to be gaining more mindshare over Apache Collections.)
Update: Note #danben and #sateesh's clarification. A BiMap would be fine if you need to get a y given an x, or an x given a y. But it sounds like you really want to look up an (x, y) point and get back a value that contains your cached information. In that case, go with #danben's suggestion.
Update: In fact, the only acceptable solution for this problem would be sorting the array ascending and then reversing it.
Let S be the following sequence of events:
Event | Time
A | 0:00
B | 0:01
C | 0:01
D | 0:02
I have a simple Comparator to sort S, which sorts the elements according to the time value.
public int compare(Event e1, Event e2) {
// Reverse sorting.
// _sortOrder is set outside this method.
if(SORT_DESCENDING.equals(_sortOrder))
return e2.getTime() - e1.getTime(); /* time is long */
return e1.getTime() - e2.getTime();
}
The problem is: when the sort order is ascending, S is sorted correctly: A, B, C, D.
But when I use reverse sorting, S becomes D, B, C, A:
Event | Time
D | 0:02
B | 0:01 /* B and C should be reversed */
C | 0:01
A | 0:00
This happens because the default sorting algorithm keeps the original order for elements with the same time value.
So, how do I sort it reverse without keeping the original order?
Note: I know I can sort S ascending and further simply revert it, but unfortunately this is not an option in my case.
The sorting algorithm is correct: 0.01 is 0.01. Unless there's something you're not telling us. If however you want the exact reverse order of an ascending sort then sort them in ascending order and use Collections.reverse(). By this I mean:
List<SomeObject> list = ...;
Collections.sort(list, myComparator);
Collections.reverse(list);
which will give you exactly what you want.
But if reversing isn't an option you only have two options left:
Make it so no two elements can be "equal". Either include another field or add a synthetic one (such as the current index or the primary key if it is a number). This will give you a reproducible, consistent and mirrored order; or
Implement your own sorting algorithm. This is not recommended as it's simply too error prone.
Now before you say you can't reverse (why?), let me ask you how you're sorting? if you're using Collections.sort() consider the source code (Java 6u10):
public static <T extends Comparable<? super T>> void sort(List<T> list) {
Object[] a = list.toArray();
Arrays.sort(a);
ListIterator<T> i = list.listIterator();
for (int j=0; j<a.length; j++) {
i.next();
i.set((T)a[j]);
}
}
So it copies the collection into an array, sorts that array and then uses that to reorder the collection.
Are you sure you can't afford a reversal?
What are you using to sort? My guess is it's something which guarantees it's a stable sort - and you've got two equal values, as far as the comparison is concerned.
Is there any additional ordering you can impose in this case? Can you easily tell which event would come first in the ascending ordering? If so, just make the original comparison use that as well, and then your descending ordering will start to work naturally.
EDIT: As your data doesn't have any extra ordering information in it, I wouldn't be surprised if it were returned in different orders when you performed the same query again in Oracle. However, if you only care about the order in this one particular case, I suggest you add an extra field in your Java in-memory representation to store the original index in the loaded list - as you read the data, keep track of how many you've read and assign the field accordingly. Then you can use that when you sort.
Am I missing something, or couldn't you just use the event name (or whatever A, B, C and D are) as secondary sort key? Just extend your Comparator to something like:
public int compare(Event e1, Event e2) {
int cmp = e1.getTime() - e2.getTime(); // compare times
if (cmp == 0) // if times are equal, compare names instead
cmp = e1.getName().compareTo(e2.getName());
return SORT_DESCENDING.equals(_sortOrder)? -cmp : cmp;
}
I think what you really want is a secondary sort criteria, such that you can sort the items even if the primary sort criteria considers the items equal. In your example, the primary criteria would be time, and secondary would be Event. This way, you don't have to rely on the items being in a certain order before performing the sort, which makes things a lot easier.
If you really don't have a secondary criteria, you would likely need to look into stable vs. unstable sorting algorithms, like Jon Skeet mentioned.
Another way but don't solve your problem :
List<SomeObject> list = ...;
Collections.sort(list, Collections.<SomeObject>reverseOrder());
Why is 0:01 smaller/larger than 0:01, or why should it be sorted in a very special way if they’re both the same?
You’re not looking for a reverse sort, you’re looking for a reversed sort, sorry. :)
Sort order does look correct, just compare the names if e1.getTime() == e2.getTime().
Depending on how fast comparing two elements is in comparison to switching them, you could just do a descending stable sort, and then reverse only all regions of "equal" elements.