4

I have a list of strings def123, abc999, zzz000, abc123, zzz111. I want the list sorted such that first three characters are sorted in ascendng order and next three in descending. So the output should be abc999, abc123, def123, zzz111,zzz000 Is this possible?

Saurav Sahu
  • 13,038
  • 6
  • 64
  • 79
Tejashwini
  • 95
  • 1
  • 12
  • 5
    Everything is possible, but SO if you want help you need to show some attempt to solve the problem. So I'll point you in the right direction. You need to implement Comparable, http://stackoverflow.com/questions/2784514/sort-arraylist-of-custom-objects-by-property – Leon Sep 12 '16 at 05:50
  • Comparable does not fit here, since Strings are final. – Sharon Ben Asher Sep 12 '16 at 05:51
  • (`Comparable does not fit here, since Strings are final` - applies _if_ `string` from the question is `java.lang.String`. (Then, there are things like [AspectJ](http://eclipse.org/aspectj)…).) – greybeard Sep 12 '16 at 06:55

5 Answers5

7

Other answers have suggested you implement Comparator. That's no longer necessary with recent utility methods added to the interface in Java 8:

list.sort(Comparator
    .comparing(s -> s.substring(0, 3))
    .thenComparing(s -> s.subtring(3, 6), Comparator.reverseOrder()));

Also note that List now has a sort method.

Supun Wijerathne
  • 11,964
  • 10
  • 61
  • 87
sprinter
  • 27,148
  • 6
  • 47
  • 78
2

Yes, it is possible. You will have to write your own Comparator. Here's a tutorial to get you started https://www.tutorialspoint.com//java/java_using_comparator.htm

Sharon Ben Asher
  • 13,849
  • 5
  • 33
  • 47
  • 1
    That tutorial is now very out-of-date. Java 8's enhancements to Comparator means that it is generally not necessary to override `compare`. Having said that, Oracle's tutorial on building comparators is equally out-of-date! – sprinter Sep 12 '16 at 07:15
2

Break the strings into two substrings and then sort using comparator. Something like this: Demo

List<String> list = Arrays.asList("def123", "abc999", "zzz000", "abc123", "zzz111");

Comparator<String> cmp = new Comparator<String>() {
  public int compare(String o1, String o2) {
    int diff = (o1.substring(0,3)).compareTo(o2.substring(0,3));
        return (diff == 0) ? (Integer.valueOf(o2.substring(3)).compareTo(Integer.valueOf(o1.substring(3)))): diff;
  }
};
Collections.sort(list, cmp);
Saurav Sahu
  • 13,038
  • 6
  • 64
  • 79
  • I like sprinter suggested solution more...+1 to him...:) – Saurav Sahu Sep 12 '16 at 06:37
  • In this special case, where the source strings have equal lengths with leading zeros where necessary, you can just compare the strings without parsing them to `int`s. – Holger Sep 13 '16 at 15:42
0

You should create a custom class including your String as an attribute. That class should implement the Comparable interface.

Inside your custom class you have to override method compareTo(T o) which was inherited from Comparable interface. You should apply your sorting logic there.

Then if you make a Collection (ex: List<CustomClass>) using that custom class as the object type, you can use Collections.sort(list) method to sort that List.

A complete example can be found here.

Supun Wijerathne
  • 11,964
  • 10
  • 61
  • 87
-1

If you want more of an algorithmic approach, check this out: https://jsfiddle.net/5adpqgrc/1/

// start with ['def123', 'abc999', 'zzz000', 'abc123', 'zzz111']
var strings = ['def123', 'abc999', 'zzz000', 'abc123', 'zzz111']
$('body').append(strings.join(' ') + '<br>')

// reverse the digits
// get this ['def876', 'abc000', 'zzz999', 'abc876', 'zzz888']
strings = reverse_digits_only(strings)
$('body').append(strings.join(' ') + '<br>')

// sort it
// get this ['abc000', 'abc876', 'def876', 'zzz888', 'zzz999']
strings = strings.sort()
$('body').append(strings.join(' ') + '<br>')

// reverse the digits again
// get this ['abc999' 'abc123' 'def123' 'zzz111' 'zzz000']
strings = reverse_digits_only(strings)
$('body').append(strings.join(' ') + '<br>')


function reverse_digits_only (strings) {
    return strings.map(function (string) {
        var first_three_letters = string.substring(0, 3)
        var reversed_digits = string.substring(3).split('').map(function (digit) {
            return 9 - digit
        })

        return first_three_letters + reversed_digits.join('')
    })
}

How this works is that you:

  1. Reverse the digits (abc999 becomes abc000)
  2. Then sort it naturally
  3. And then reverse the digits again.
Martin Gottweis
  • 2,721
  • 13
  • 27