43

In Java, I have a data in my array like the following

2009.07.25 20:24 Message A
2009.07.25 20:17 Message G
2009.07.25 20:25 Message B
2009.07.25 20:30 Message D
2009.07.25 20:01 Message F
2009.07.25 21:08 Message E
2009.07.25 19:54 Message R

I would like to sort it based on the first column, so my final data can look like this

2009.07.25 19:54 Message R
2009.07.25 20:01 Message F
2009.07.25 20:17 Message G
2009.07.25 20:24 Message A
2009.07.25 20:25 Message B
2009.07.25 20:30 Message D
2009.07.25 21:08 Message E

The first column is a date of format "yyyy.MM.dd HH:mm" and the second column is a String.

Raj
  • 22,346
  • 14
  • 99
  • 142

8 Answers8

81

Sort a two dimensional array based on one column
The first column is a date of format "yyyy.MM.dd HH:mm" and the second column is a String.

Since you say 2-D array, I assume "date of format ..." means a String. Here's code for sorting a 2-D array of String[][]:

import java.util.Arrays;
import java.util.Comparator;

public class Asdf {

    public static void main(final String[] args) {
        final String[][] data = new String[][] {
                new String[] { "2009.07.25 20:24", "Message A" },
                new String[] { "2009.07.25 20:17", "Message G" },
                new String[] { "2009.07.25 20:25", "Message B" },
                new String[] { "2009.07.25 20:30", "Message D" },
                new String[] { "2009.07.25 20:01", "Message F" },
                new String[] { "2009.07.25 21:08", "Message E" },
                new String[] { "2009.07.25 19:54", "Message R" } };

        Arrays.sort(data, new Comparator<String[]>() {
            @Override
            public int compare(final String[] entry1, final String[] entry2) {
                final String time1 = entry1[0];
                final String time2 = entry2[0];
                return time1.compareTo(time2);
            }
        });

        for (final String[] s : data) {
            System.out.println(s[0] + " " + s[1]);
        }
    }

}

Output:

2009.07.25 19:54 Message R
2009.07.25 20:01 Message F
2009.07.25 20:17 Message G
2009.07.25 20:24 Message A
2009.07.25 20:25 Message B
2009.07.25 20:30 Message D
2009.07.25 21:08 Message E
Bert F
  • 85,407
  • 12
  • 106
  • 123
  • 2
    simple! I tried it and it worked as expected - thanks - marking as the correct answer – Raj Feb 05 '11 at 17:36
  • @emaillenin - I'm glad that I could help – Bert F Feb 05 '11 at 19:59
  • @BertF, Helpful. If I want to compare in natural order, what should I do? And +1 for Nice Answer. :) – Md Mahbubur Rahman Jan 04 '13 at 05:51
  • How do you choose which array value to sort by? for example String[][] cat = new String[13][4]; I want to sort by the 3rd column in each row. – Rick Apr 18 '14 at 20:45
  • 2
    @Rick you simply change the code in the `public int Compare...` method to specify the column you want to sort by. `[0]` means first column so for fourth column use `[3]`. – Troyseph Nov 03 '14 at 12:08
12
class ArrayComparator implements Comparator<Comparable[]> {
    private final int columnToSort;
    private final boolean ascending;

    public ArrayComparator(int columnToSort, boolean ascending) {
        this.columnToSort = columnToSort;
        this.ascending = ascending;
    }

    public int compare(Comparable[] c1, Comparable[] c2) {
        int cmp = c1[columnToSort].compareTo(c2[columnToSort]);
        return ascending ? cmp : -cmp;
    }
}

This way you can handle any type of data in those arrays (as long as they're Comparable) and you can sort any column in ascending or descending order.

String[][] data = getData();
Arrays.sort(data, new ArrayComparator(0, true));

PS: make sure you check for ArrayIndexOutOfBounds and others.

EDIT: The above solution would only be helpful if you are able to actually store a java.util.Date in the first column or if your date format allows you to use plain String comparison for those values. Otherwise, you need to convert that String to a Date, and you can achieve that using a callback interface (as a general solution). Here's an enhanced version:

class ArrayComparator implements Comparator<Object[]> {
    private static Converter DEFAULT_CONVERTER = new Converter() {
        @Override
        public Comparable convert(Object o) {
            // simply assume the object is Comparable
            return (Comparable) o;
        }
    };
    private final int columnToSort;
    private final boolean ascending;
    private final Converter converter;


    public ArrayComparator(int columnToSort, boolean ascending) {
        this(columnToSort, ascending, DEFAULT_CONVERTER);
    }

    public ArrayComparator(int columnToSort, boolean ascending, Converter converter) {
        this.columnToSort = columnToSort;
        this.ascending = ascending;
        this.converter = converter;
    }

    public int compare(Object[] o1, Object[] o2) {
        Comparable c1 = converter.convert(o1[columnToSort]);
        Comparable c2 = converter.convert(o2[columnToSort]);
        int cmp = c1.compareTo(c2);
        return ascending ? cmp : -cmp;
    }

}

interface Converter {
    Comparable convert(Object o);
}

class DateConverter implements Converter {
    private static final DateFormat df = new SimpleDateFormat("yyyy.MM.dd hh:mm");

    @Override
    public Comparable convert(Object o) {
        try {
            return df.parse(o.toString());
        } catch (ParseException e) {
            throw new IllegalArgumentException(e);
        }
    }
}

And at this point, you can sort on your first column with:

Arrays.sort(data, new ArrayComparator(0, true, new DateConverter());

I skipped the checks for nulls and other error handling issues.

I agree this is starting to look like a framework already. :)

Last (hopefully) edit: I only now realize that your date format allows you to use plain String comparison. If that is the case, you don't need the "enhanced version".

Costi Ciudatu
  • 37,042
  • 7
  • 56
  • 92
  • 1
    +1, for the more general solution to sort by any Object and on any column. – camickr Feb 05 '11 at 16:31
  • It's a good general solution, but the question as posed asks for sorting of a `String[]` where each `String` contains columnar data. The title doesn't match the question; this answer satisfies the title only... – dkarp Feb 05 '11 at 16:34
8
Arrays.sort(yourarray, new Comparator() {
    public int compare(Object o1, Object o2) {
        String[] elt1 = (String[])o1;
        String[] elt2 = (String[])o2;
        return elt1[0].compareTo(elt2[0]);
    }
});
Bert F
  • 85,407
  • 12
  • 106
  • 123
Ron
  • 1,932
  • 20
  • 17
7
  1. install java8 jdk+jre

  2. use lamda expression to sort 2D array.

code:

import java.util.Arrays;
import java.util.Comparator;

class SortString {

    public static void main(final String[] args) {
        final String[][] data = new String[][] {
                new String[] { "2009.07.25 20:24", "Message A" },
                new String[] { "2009.07.25 20:17", "Message G" },
                new String[] { "2009.07.25 20:25", "Message B" },
                new String[] { "2009.07.25 20:30", "Message D" },
                new String[] { "2009.07.25 20:01", "Message F" },
                new String[] { "2009.07.25 21:08", "Message E" },
                new String[] { "2009.07.25 19:54", "Message R" } 
        };
        // this is applicable only in java 8 version.
        Arrays.sort(data, (String[] s1, String[] s2) -> s1[0].compareTo(s2[0]));

        // we can also use Comparator.comparing and point to Comparable value we want to use        
        // Arrays.sort(data, Comparator.comparing(row->row[0]));

        for (final String[] s : data) {
            System.out.println(s[0] + " " + s[1]);
        }
    }
}

output

2009.07.25 19:54 Message R
2009.07.25 20:01 Message F
2009.07.25 20:17 Message G
2009.07.25 20:24 Message A
2009.07.25 20:25 Message B
2009.07.25 20:30 Message D
2009.07.25 21:08 Message E
Pshemo
  • 122,468
  • 25
  • 185
  • 269
5

Assuming your array contains strings, you can use the following:

String[] data = new String[] { 
    "2009.07.25 20:24 Message A",
    "2009.07.25 20:17 Message G",
    "2009.07.25 20:25 Message B",
    "2009.07.25 20:30 Message D",
    "2009.07.25 20:01 Message F",
    "2009.07.25 21:08 Message E",
    "2009.07.25 19:54 Message R"
};

Arrays.sort(data, new Comparator<String>() {
    @Override
    public int compare(String s1, String s2) {
        String t1 = s1.substring(0, 16); // date/time of s1
        String t2 = s2.substring(0, 16); // date/time of s2
        return t1.compareTo(t2);
    }
});

If you have a two-dimensional array, the solution is also very similar:

String[][] data = new String[][] { 
        { "2009.07.25 20:17", "Message G" },
        { "2009.07.25 20:25", "Message B" },
        { "2009.07.25 20:30", "Message D" },
        { "2009.07.25 20:01", "Message F" },
        { "2009.07.25 21:08", "Message E" },
        { "2009.07.25 19:54", "Message R" }
};

Arrays.sort(data, new Comparator<String[]>() {
    @Override
    public int compare(String[] s1, String[] s2) {
        String t1 = s1[0];
        String t2 = s2[0];
        return t1.compareTo(t2);
    }
});
João Silva
  • 89,303
  • 29
  • 152
  • 158
  • @dogbane Take a look at the question. It's *not* actually a 2D array, even though the title insists that it is. It's an array of `String`s with columnar data inside. In fact, this response addresses the actual question better than all the others... – dkarp Feb 05 '11 at 16:15
  • 1
    @dkarp why are you comparing just the times? You should be comparing the first column which is "yyyy.MM.dd HH:mm". Take another look at the question. – dogbane Feb 05 '11 at 16:19
  • @dogbane Oh, that's a good point. (Not my answer, however.) Still, a *good* answer to this question should treat it as a `String[]` with columnar data in the format described by the OP, not as a `String[][]`. I'd de-upvote this one if I'd seen your comment earlier, though... – dkarp Feb 05 '11 at 16:23
  • @dogbane and @dkarp: Thanks, I have edited my answer to include date/time instead of just time. I have also added a version to sort a two-dimensional array, though it is not clear to me given the example the OP provided that he is working with a 2D array. – João Silva Feb 05 '11 at 16:27
  • @dkarp sorry, thought it was your answer. – dogbane Feb 05 '11 at 16:27
3

Using Lambdas since java 8:

final String[][] data = new String[][] { new String[] { "2009.07.25 20:24", "Message A" },
        new String[] { "2009.07.25 20:17", "Message G" }, new String[] { "2009.07.25 20:25", "Message B" },
        new String[] { "2009.07.25 20:30", "Message D" }, new String[] { "2009.07.25 20:01", "Message F" },
        new String[] { "2009.07.25 21:08", "Message E" }, new String[] { "2009.07.25 19:54", "Message R" } };
String[][] out = Arrays.stream(data).sorted(Comparator.comparing(x -> x[1])).toArray(String[][]::new);

System.out.println(Arrays.deepToString(out));
    

Output:

[[2009.07.25 20:24, Message A], [2009.07.25 20:25, Message B], [2009.07.25 20:30, Message D], [2009.07.25 21:08, Message E], [2009.07.25 20:01, Message F], [2009.07.25 20:17, Message G], [2009.07.25 19:54, Message R]]

Community
  • 1
  • 1
ΦXocę 웃 Пepeúpa ツ
  • 47,427
  • 17
  • 69
  • 97
3

Check out the ColumnComparator. It is basically the same solution as proposed by Costi, but it also supports sorting on columns in a List and has a few more sort properties.

camickr
  • 321,443
  • 19
  • 166
  • 288
3

If you are looking for easy one liners to sort 2d array, then here you go.


Sort String[][] arr in ascending order by first column

Arrays.sort(arr, (a, b) -> a[0].compareTo(b[0]);

Sort String[][] arr in descending order by first column

Arrays.sort(arr, (a, b) -> b[0].compareTo(a[0]);

Sort String[][] arr in ascending order by second column

Arrays.sort(arr, (a, b) -> a[1].compareTo(b[1]);

Sort String[][] arr in descending order by second column

Arrays.sort(arr, (a, b) -> b[1].compareTo(a[1]);

Sort int[][] arr in ascending order by first column

Arrays.sort(arr, (a, b) -> Integer.compare(a[0], b[0]));

or

Arrays.sort(arr, (a, b) -> a[0] - b[0]);

Sort int[][] arr in descending order by first column

Arrays.sort(arr, (a, b) -> Integer.compare(b[0], a[0]));

or

Arrays.sort(arr, (a, b) -> b[0] - a[0]);

Sort int[][] arr in ascending order by second column

Arrays.sort(arr, (a, b) -> Integer.compare(a[1], b[1]));

or

Arrays.sort(arr, (a, b) -> a[1] - b[1]);

Sort int[][] arr in descending order by second column

Arrays.sort(arr, (a, b) -> Integer.compare(b[1], a[1]));

or

Arrays.sort(arr, (a, b) -> b[1] - a[1]);
luckyguy73
  • 1,850
  • 2
  • 11
  • 21