Reputation: 628
I have a List of objects each of which has a method getNumOrder that returns a string. The objects in the list are sorted in lexicographical order. Most of the times all the objects in the list have getNumOrder that return an integer (but not always).
If all the elements in the lists have NumOrders that are integers I would like to sort them using integer sort order. Otherwise they will remain sorted lexicographically.
I have tried this using Java 8 Lambdas
try {
results.sort((r1,r2)-> {
Integer seq1= new Integer(r1.getNumOrder());
Integer seq2= new Integer(r2.getNumOrder());
seq1.compareTo(seq2);
});
}
catch (Exception e) {
// Do nothing: Defaults to lexicographical order.
}
There are 2 issues:
Because I dont know Lambda expressions very well the syntax is incorrect
I am not sure if this will work if the sorting by integer order fails, i.e. whether it will leave the list sorted lexicographically.
Upvotes: 3
Views: 4060
Reputation: 740
In order to make your code work, just return "seq1.compareTo(seq2);" like this:
try {
results.sort((r1,r2)-> {
Integer seq1= new Integer(r1.getNumOrder());
Integer seq2= new Integer(r2.getNumOrder());
return seq1.compareTo(seq2);
});
}
catch (Exception e) {
// Do nothing: Defaults to lexicographical order.
}
As @Andreas pointed out in the comments, it shouldn't be done that way (with boxing and with using the constructor to parse a String to an integer), there is a cleaner and "not so wastful" way to accomplish that. Here's the code:
try {
results.sort((r1,r2)->
Integer.compare(Integer.parseInt(r1.getNumOrder()),
Integer.parseInt(r2.getNumOrder()))
);
}
catch (Exception e) {
// Do nothing: Defaults to lexicographical order.
}
Remember here that you only need to (explicitly) return a value in lambdas when you use brackets, as its then handled like a method which - in the case of "sort" - should return an Integer.
Upvotes: 2
Reputation: 159086
Do not use new Integer(String)
to parse a number. It has been deprecated in Java 9. Use Integer.parseInt(String s)
instead, or Integer.valueOf(String s)
if you insists on boxing the value (a waste in this case).
The lambda you're after would be:
results.sort((r1,r2) -> Integer.compare(Integer.parseInt(r1.getNumOrder()),
Integer.parseInt(r2.getNumOrder())));
This leaves results
unmodified if the sort fails, because the sort()
method copies the list elements to an array, sorts the array, then copies the elements back.
If you prefer to store intermediate values in variables, e.g. so you can see them when debugging, you will be using a lambda block and it needs a return
statement. That's what is missing in your code.
results.sort((r1,r2) -> {
int i1 = Integer.parseInt(r1.getNumOrder());
int i2 = Integer.parseInt(r2.getNumOrder());
return Integer.compare(i1, i2);
});
The below part of the answer was based on misunderstanding that input was list of strings, which it's not, so it doesn't apply to question, but I'm leaving it for others who might have similar problems where input is a list of strings.
But it's not good performance. If strings don't have leading zeroes that need to be retained, it'd be better to parse to int
, sort the int
values, then format back to string.
Using streams (Java 8+):
results = results.stream()
.mapToInt(Integer::parseInt)
.sorted()
.mapToObj(Integer::toString)
.collect(Collectors.toList());
Or this non-stream version (Java 1.2+):
int[] arr = new int[results.size()];
int i = 0;
for (String s : results)
arr[i++] = Integer.parseInt(s);
Arrays.sort(arr);
results.clear();
for (int v : arr)
results.add(Integer.toString(v));
Upvotes: 4
Reputation: 633
You just forgot a "return" in your lambda :
return seq1.compareTo(seq2);
Other than that, seems fine, even if it fails
Upvotes: 1