Java 对二维字符串数组中的列进行排序

问题描述 投票:0回答:5

我一直在解决这个问题。但是,我的数据排列略有不同。

无需讨论如何检索数据,只要说结果数组看起来像这样就足够了

String[2][]
    [0] = String[4]
    [1] = String[4]

实际数据如下

data = String[2][]
  data[0]
    data[0][0] = "Columbia"
    data[0][1] = "Chile"
    data[0][2] = "Asia"
    data[0][3] = "US"
  data[1]
    data[1][0] = "B216"
    data[1][1] = "B217"
    data[1][2] = "A442"
    data[1][3] = "N665"

我想按 data[0] 按字母顺序对整个数组进行排序。然而我意识到所引用的 SO 问题中提供的解决方案正在使用不同的数组格式。

我的预期结果会是这样的

data = String[2][]
  data[0]
    data[0][0] = "Asia"
    data[0][1] = "Chile"
    data[0][2] = "Columbia"
    data[0][3] = "US"
  data[1]
    data[1][0] = "A442"
    data[1][1] = "B217"
    data[1][2] = "B216"
    data[1][3] = "N665"

我不完全确定如何在不迭代每个元素并将它们转移到新数组的情况下获得这些结果。

有什么想法吗?

java arrays sorting
5个回答
1
投票

完整代码这里

  1. String[]
    的内部
    data
    进行排序。
  2. data
    添加到
    ArrayList

    List<String[]> list = new ArrayList<>();
    // Sort the String array and insert it in List
    for (String dataArr[] : data) {
        String s[] = dataArr.clone(); // create new object of String array
        Arrays.sort(s); // Sort newly created String array
        list.add(s);
    }
    
  3. 使用自定义比较器对此列表进行排序。
    3.1 请记住,您需要扫描比较中的两个数组的整个

    String[]
    才能找到第一个差异。

    // Sort the list using custom comparator
    Collections.sort(list, new Comparator<String[]>() {
    
        @Override
        public int compare(String[] o1, String[] o2) {
    
            // optional: condition to check for string length equality
            if (o1.length == o2.length) {
                for (int i = 0; i < o1.length; i++) {
                    if (o1[i].equals(o2[i])) { // ** IMP **
                        // allows scanning through entire string array.
                        continue;
                    }
                    // Find the first different strings in both arrays
                    return o1[i].compareTo(o2[i]);
                }
            } else if (o1.length < o2.length) {
                // allow string arrays with lesser elements to appear first
                return -1;
            } else if (o1.length > o2.length) {
                return 1;
            }
    
            // When o1.length == o2.length and all strings are equal
            return 0; // no difference
        }
    
    });
    

数据(第一行)和排序列表的示例输出


1
投票

我可以看到如何将多个数组按相同顺序排序的三个选项:

  1. 创建一个索引数组,使用

    Comparator
    对其进行排序,

    Integer[] indices = new Integer[data[0].length]; for(int i = 0; i < data[0].length; i++) indices[i] = i; Arrays.sort(indices, new Comparator<Integer>() { @Override public int compare(Integer i1, Integer i2) { return data[0][i1].compareTo(data[0][i2]); } });
     指的是要根据索引进行排序的数组,然后根据排序后的索引重新排列数组。这是一个示例:

    Integer

    
    
    索引数组必须是
    int
    类型而不是
    Arrays
    类型,因为

    public String[] rearrange(Integer[] indices, String[] input) { String[] output = new String[]; for(int i = 0; i < indices.length; i++) output[i] = input[indices[i]]; return output; }
     不允许使用自定义比较器对基元进行排序。然后,您可以通过索引数组重新排列两个数组,执行类似于下面的函数的操作。我想不出一种方法可以在不打乱顺序并使索引数组无效的情况下就地执行此操作。

    for(int i = 0; i < data.length; i++) data[i] = rearrange(indices, data[i]);

    此函数不会进行错误检查以查看输入是否具有相同的长度,并且它不使用流,我确信可以重写它来做到这一点。这只是这个概念的一个例子。使用方法:

    Comparable 这可能是重新排列数组时占用内存最少的选项。它的灵感来自于这个答案

    问题
  2. 的回答,我认为它与你的答案重复。
  3. 创建一个对象来保存给定索引处的所有元素,并使其成为public class Container implements Comparable<Container>
    {
        public final String country;
        public final String code;
    
        public Container(Sting country, String code)
        {
            this.country = country;
            this.code = code;
        }
    
        public int compareTo(Container other)
        {
            return this.country.compareTo(other.country);
        }
    }
    。这是之前提到的问题

    已接受答案
    的解决方案。

    objects = new Container[data[0].length]; for(int i = 0; i < objects.length; i++) objects[i] = new Container(data[0][i], data[1][i]); Arrays.sort(objects);

    您必须将数据转换为这些容器的数组,然后对其进行排序:

    List

    
    
    虽然此方法确实需要将数据复制为不同的格式,但它实际上比使用数组数组更强大,因为它将概念上相关的项目分组为单个项目。这完全消除了检查数组长度是否相等之类的需要,并且通常更加面向对象。您甚至可以重写数据输入以仅吐出一个数组或
    Container
    对象,而不是 2D 数组。

  4. 在国家/地区和代码之间创建显式映射,然后根据排序的键取消引用值。这有点像 #1 所做的,但它至少允许您就地对其中一个数组进行排序。如果映射是有序映射,直接转成有序数组即可。

    a.未排序的映射:

    HashMap<String, String> mapping = new HashMap<>();
    for(int i = 0; i < data[0].length; i++)
        mapping.put(data[0][i], data[1][i]);
    Arrays.sort(data[0]);
    
    String[] outputCodes = new String[data[1].length];
    for(int i = 0; i < outputCodes.length; i++)
        outputCodes[i] = mapping(data[0][i]);
    data[1] = outputCodes;
    

    b.排序映射:

    TreeMap<String, String> mapping = new TreeMap<>();
    for(int i = 0; i < data[0].length; i++)
        mapping.put(data[0][i], data[1][i]);
    data[0] = new String[mapping.size()];
    data[1] = new String[mapping.size()];
    int index = 0;
    for(Map.Entry<String, String> entry : mapping.entrySet()) {
        data[0][index] = entry.getKey();
        data[1][index] = entry.getValue();
        index++;
    }
    

    这些方法都有一个缺点,即它们只适用于两列数据。如果您有更多,您的值必须成为自定义对象或对象数组或类似的东西。无论哪种方式,这种方法都相当笨重,我提供它只是为了说明如果您确实愿意的话,如何可以跳过额外的障碍。

可能还有其他方法,但正如#3所示,我怀疑与此处显示的三种方法相比,它们在速度、内存或易读性/可维护性方面不会特别有效。

另请记住,流可以让您更轻松地完成我在此处向您展示的所有操作。


0
投票

尝试一下。非常适合我。

        Map<String, String> unsortMap = new HashMap<>();
                unsortMap.put("Columbia", "B216");
                unsortMap.put("Chile", "B217");
                unsortMap.put("Asia", "A442");
                unsortMap.put("US", "N665");

                System.out.println("Original...");
                System.out.println(unsortMap);

                Map<String, String> result = new LinkedHashMap<>();

                //sort by key, a,b,c..., and put it into the "result" map
                unsortMap.entrySet().stream()
                        .sorted(Map.Entry.<String, String>comparingByKey())
                        .forEachOrdered(x -> result.put(x.getKey(), x.getValue()));

                System.out.println("Sorted...");
                System.out.println(result);

0
投票

解决方案

采纳 Socowi 和 Stephen P 的建议并同时对多个数组进行排序我想出了以下解决方案

当我将此数据返回到 JSP 以填充下拉菜单时,我为模型添加了一个类,并迭代数组,将模型类的新实例添加到数组列表中

for (int i = 0; i < data[0].length; i++) {
  dataList.add(new LocationModel(data[0][i], data[1][i].trim()));
}

模型类实现Comparable并重写compareTo方法

public class LocationModel implements Comparable<LocationModel> {
  ...
  @Override
    public int compareTo(LocationModel other) {
        return this.locName.compareToIgnoreCase(other.getLocName());
    }
}

然后我简单地对数组列表进行排序

Collections.sort(dataList);

这解决了我的问题。

感谢大家的协助


0
投票

包 com.mycompany.stringsortingby2darray;

公共类 StringSortingby2dArray {

public static void main(String[] args) {

字符串数据[][]= {{"MADHYAPRADESH",String.valueOf(1)},{"BHARAT",String.valueOf(2)},{"美国",String.valueOf(13)},{"澳大利亚",String.valueOf(17)},{"UTTARPRADESH",String.valueOf(5)}};

    for (int i = 0; i < data.length; i++) {
        //for (int j = 0; j < data.length; j++) {
            System.out.println(data[i][0]);
        }
    }

}
© www.soinside.com 2019 - 2024. All rights reserved.