基于一列,对一个二维数组进行排序

43

在Java中,我有一个数组,其中包含以下数据

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

我想根据第一列进行排序,以便我的最终数据看起来像这样

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

第一列是"yyyy.MM.dd HH:mm"格式的日期,第二列是字符串。

8个回答

81

如何基于一列对一个二维数组进行排序
第一列是格式为“yyyy.MM.dd HH:mm”的日期,第二列是字符串。

由于您提到了2-D数组,我假设“格式为...”指的是字符串。下面是对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]);
        }
    }

}

输出:

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

2
简单!我尝试了一下,它按预期工作了 - 谢谢 - 标记为正确答案。 - Raj
@emaillenin - 我很高兴我能帮助到你。 - Bert F
@BertF,非常有帮助。如果我想按自然顺序比较,应该怎么做?并为漂亮的回答点+1。 :) - Md Mahbubur Rahman
你如何选择按哪个数组值进行排序?例如,String[][] cat = new String[13][4]; 我想按每行的第三列进行排序。 - Rick
2
@Rick,你只需更改public int Compare...方法中的代码以指定要按其排序的列。[0]表示第一列,因此要使用第四列,请使用[3] - Troyseph

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;
    }
}

通过这种方式,您可以处理这些数组中的任何类型数据(只要它们是可比较的),并且可以按升序或降序对任何列进行排序。

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

PS:确保检查ArrayIndexOutOfBounds和其他错误。

编辑:上述解决方案只有在您能够实际存储java.util.Date在第一列中,或者如果您的日期格式允许您对这些值使用纯字符串比较时才有帮助。否则,您需要将该字符串转换为日期,并且可以使用回调接口(作为一般解决方案)来实现。以下是增强版本:

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);
        }
    }
}

现在,您可以使用以下代码对第一列进行排序:

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

我跳过了对空值和其他错误处理问题的检查。

我同意这看起来已经像一个框架了。:)

最后(希望如此)编辑:我现在才意识到您的日期格式允许您使用纯字符串比较。如果是这种情况,您不需要“增强版”。


1
+1,对于更通用的解决方案,可以按任何对象和任何列进行排序。 - camickr
这是一个不错的通用解决方案,但问题所要求的是对包含列数据的String[]进行排序。标题与问题不匹配;此答案仅满足标题... - dkarp

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]);
    }
});

7
  1. 安装Java8 JDK+JRE

  2. 使用lambda表达式二维数组进行排序。

代码:

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]);
        }
    }
}

输出

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

5
假设您的数组包含字符串,则可以使用以下方法:
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);
    }
});

如果您有一个二维数组,解决方案也非常相似:
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);
    }
});

@dogbane 看一下这个问题。尽管标题坚称它是一个二维数组,但实际上它并不是。它是一个包含列数据的字符串数组。事实上,这个回答比其他所有回答更好地解决了实际问题... - dkarp
1
@dkarp 为什么你只比较时间?你应该比较第一列,即“yyyy.MM.dd HH:mm”。再看一下问题。 - dogbane
@dogbane 哦,那是个好观点。(不是我的答案。)然而,对于这个问题来说,一个好的答案应该将其视为一个String[],其中包含按照OP描述的格式排列的列数据,而不是一个String[][]。如果我早些看到你的评论,我会取消点赞的... - dkarp
@dogbane和@dkarp:谢谢,我已经编辑了我的答案,包括日期/时间而不仅仅是时间。我还添加了一个版本来对二维数组进行排序,尽管根据OP提供的示例,他是否正在使用2D数组并不清楚。 - João Silva
@dkarp 抱歉,我以为那是你的答案。 - dogbane

3

看看ColumnComparator。它基本上是与Costi提出的解决方案相同,但还支持对列表中的列进行排序,并具有更多的排序属性。


3

自Java 8以来,使用Lambda表达式:

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));
    

输出:

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

这是一个输出结果,包含了时间和消息的列表。请注意保留HTML标记。

3

如果您正在寻找简单的一句话来排序二维数组,那么请看这里。


按第一列升序排序String[][] arr

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

按第一列降序排列字符串二维数组arr。
Arrays.sort(arr, (a, b) -> b[0].compareTo(a[0]);

按第二列升序对字符串数组 String[][] arr 进行排序

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

按照第二列降序排列String[][] arr
Arrays.sort(arr, (a, b) -> b[1].compareTo(a[1]);

按第一列将 int[][] 数组升序排序。
Arrays.sort(arr, (a, b) -> Integer.compare(a[0], b[0]));

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

按第一列降序排列int[][] arr
Arrays.sort(arr, (a, b) -> Integer.compare(b[0], a[0]));

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

按第二列升序排序 int[][] arr

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

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

按第二列降序排序 int[][] arr
Arrays.sort(arr, (a, b) -> Integer.compare(b[1], a[1]));

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接