views:

5469

answers:

7

I have an array of filenames and need to sort that array by the extensions of the filename. Is there an easy way to do this?

+4  A: 

If I remember correctly, the Arrays.sort(...) takes a Comparator<> that it will use to do the sorting. You can provide an implementation of it that looks at the extension part of the string.

Matthew Brubaker
+3  A: 

You can implement a custom Comparator of Strings. Make it sort them by the substring after the last index of '.'. Then pass in the comparator and your array into

Arrays.sort(stringArray, yourComparator);

//  An implementation of the compare method
public int compare(String o1, String o2) {
    return o1.substring(o1.lastIndexOf('.')).compareTo(o2.substring(o2.lastIndexOf('.'));
}
jjnguy
+1  A: 

Create a Comparator and compare the string extensions. Take a look at the following

http://java.sun.com/j2se/1.4.2/docs/api/java/util/Comparator.html

Then pass in your List of strings to Arrays.sort(List, Comparator)

ng
+1  A: 

Create your own Comparator that treats the strings as filenames and compares them based on the extensions. Then use Arrays.sort with the Comparator argument.

Glomek
+15  A: 
Arrays.sort(filenames, new Comparator<String>() {
    @Override
    public int compare(String s1, String s2) {
        // the +1 is to avoid including the '.' in the extension and to avoid exceptions
        // EDIT:
        // We first need to make sure that either both files or neither file
        // has an extension (otherwise we'll end up comparing the extension of one
        // to the start of the other, or else throwing an exception)
        final int s1Dot = s1.lastIndexOf('.');
        final int s2Dot = s2.lastIndexOf('.');
        if ((s1Dot == -1) == (s2Dot == -1)) { // both or neither
            s1 = s1.substring(s1Dot + 1);
            s2 = s2.substring(s2Dot + 1);
            return s1.compareTo(s2);
        } else if (s1Dot == -1) { // only s2 has an extension, so s1 goes first
            return -1;
        } else { // only s1 has an extension, so s1 goes second
            return 1;
        }
    }
});

For completeness: java.util.Arrays and java.util.Comparator.

Michael Myers
Including the '.' won't change anything significant in this instance.
Matthew Brubaker
No, it's just an unnecessary extra comparison.
Michael Myers
Actually, come to think of it, it does make a difference: if there is no extension, the +1 makes it check the full filename instead of simply throwing an IndexOutOfBoundsException. That's either a bug or a brilliant hidden feature. :)
Michael Myers
Come to think of it again, it's a bug (what if only one of the files has an extension?). I'll have to edit the code to correct it.
Michael Myers
Glad you're cogitating the exact implementation ;)
Matthew Brubaker
I'd leave that up to unit testing to make sure it all works, and let the OP learn about the gotcha's involved. =P
Matthew Brubaker
Besides, one extra comparison isn't going to kill you unless you're comparing an exorbitantly large number of strings. In which case I'm left wondering why you're using strings and not File objects, but that's another question all together.
Matthew Brubaker
Yeah, I could have left the fine-tuning as an exercise to the reader, but I don't have much else to do. :D
Michael Myers
A: 

If you just want to group the files by their extension and do not care about the actual alphabetical order, you can use this:

I think the simplest thing you can do that also works when the filenname does not have a "." is to just reverse the names and compare them.

Arrays.sort(ary, new Comparator<String>() {
    @Override
    public int compare(String o1, String o2) {
        String r1 = new StringBuffer(o1).reverse().toString();
        String r2 = new StringBuffer(o2).reverse().toString();
        return r1.compareTo(r2);
    }
});

Its a shame that java's string does not even have a reverse().

martinus
You sure you want r1.compareTo(r2) and not the other way around?
Michael Myers
depends if the sort order really matters, or if you just want to group files with the same extension together.
martinus
This does not work at all, .png will sort before .jpg for example.
Christoffer Hammarström
@christoffer You are right, it does not work at all... This sorting does is just group together files with the same extension, but the order is not alphabetically. Thanks for pointing that out, Ive updated the description
martinus
+2  A: 

Comparators are often hard to get exactly right, and the comparison key has to be generated for every comparison which for most sorting algorithms mean O(n log n). Another approach is to create (key, value) pairs for each item you need to sort, put them in a TreeMap, and then ask for the values as these are sorted according to the key.

For instance

import java.util.Arrays;
import java.util.TreeMap;

public class Bar {

    public static void main(String[] args) {
     TreeMap<String, String> m2 = new TreeMap<String, String>();
     for (String string : Arrays.asList(new String[] { "#3", "#2", "#1" })) {
      String key = string.substring(string.length() - 1);
      String value = string;
      m2.put(key, value);
     }
     System.out.println(m2.values());
    }
}

prints out

[#1, #2, #3]

You should easily be able to adapt the key calculation to your problem.

This only calculates the key once per entry, hence O(n) - (but the sort is still O(n log n)). If the key calculation is expensive or n is large this might be quite measurable.

Thorbjørn Ravn Andersen