【问题标题】:Java - Custom Sort ArrayList of StringsJava - 字符串的自定义排序 ArrayList
【发布时间】:2015-09-22 04:19:02
【问题描述】:

我想按特定顺序对长度为 1 或 2 的字符串的 ArrayList 进行排序。

顺序是

1m, 2m, 3m ... 9,, 1p...9p, 1s...9s, E, S, W, N,Wd, Gd, Rd

如果你明白了?

比如ArrayList是;

N 2p 9s 9s 1p 9m N 4s 1m 5p 7m 2s 5s 5m  

我正在尝试在这个 ArrayList 是一个字段的类中编写一个方法,它将按所需的顺序放置它。

类似的问题指向比较器,但我发现每个解释都非常令人困惑,但做的事情却与我想要的不同。

只要把订单完整地写出来就可以了。

【问题讨论】:

  • 如果你明白了? 不,坦率地说,我不明白。如果你不能清楚地定义一个字符串是在另一个字符串之前还是之后的规则,那么你就无法实现它。此规则称为比较器。
  • 您对比较方法有什么困惑?这正是你需要做的。要求澄清原始问题 - 请不要再问同样的问题。
  • 您要先按数字部分排序,然后按字母部分区分大小写吗?
  • 我同意这个问题可能存在一些问题,但它强调 不是链接问题的重复。他的问题是他不明白如何为他的情况编写 compareTo 方法。以“以下是如何为已经有 compareTo 的字段构建比较器”答案的链接结尾是真的没有帮助

标签: java string sorting arraylist comparator


【解决方案1】:

既然我主张重新打开它,这里有一个 Comparator<String> 可以满足您的需求:

package testJ;

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

public class WeirdOrderComparator implements Comparator<String> {
  private static List<String> COMPASS_ORDER = Arrays.asList("E:S:W:N"
      .split(":"));
  private static List<String> D_ORDER = Arrays.asList("W:G:R".split(":"));
  private static List<String> SUFFIX_ORDER = Arrays.asList("m:p:s::d"
      .split(":"));

  private int indexFor(String target, List<String> order) {
    int r = order.indexOf(target);
    if (r < 0) {
      return order.size();
    } else {
      return r;
    }
  }

  private int getSuffixNumber(String s) {
    switch (s.length()) {
    case 1:
      return indexFor("", SUFFIX_ORDER);
    case 2:
      return indexFor(s.substring(1), SUFFIX_ORDER);
    default:
      return 99;
    }
  }

  private int getWithinGroupNumber(int suffixGroup, String s) {
    switch (suffixGroup) {
    case 0:
    case 1:
    case 2:
      return Integer.valueOf(s.substring(0, s.length() - 1));
    case 3:
      return indexFor(s, COMPASS_ORDER);
    case 4:
      return indexFor(s.substring(0, 1), D_ORDER);
    default:
      return 99;
    }
  }

  public int compare(String o1, String o2) {
    int sfx1 = getSuffixNumber(o1);
    int sfx2 = getSuffixNumber(o2);
    if (sfx1 != sfx2) {
      return sfx1 - sfx2;
    }
    int grp1 = getWithinGroupNumber(sfx1, o1);
    int grp2 = getWithinGroupNumber(sfx2, o2);
    if (grp1 != grp2) {
      return grp1 - grp2;
    }
    return o1.compareTo(o2);
  }
}

它可以用作:

package testJ;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class WeirdOrderTest {
  public static void main(String args[]) {
    List<String> testList = Arrays.asList("N 2p 9s 9s 1p 9m N 4s 1m 5p 7m 2s 5s 5m".split(" "));
    System.out.println("Original order: " + testList);
    ArrayList<String> sorted = new ArrayList<String>();
    sorted.addAll(testList);
    Collections.sort(sorted, new WeirdOrderComparator());
    System.out.println("Sorted: " + sorted);
  }
}

这会产生:

Original order: [N, 2p, 9s, 9s, 1p, 9m, N, 4s, 1m, 5p, 7m, 2s, 5s, 5m]
Sorted: [1m, 5m, 7m, 9m, 1p, 2p, 5p, 2s, 4s, 5s, 9s, 9s, N, N]

这里的一般策略是:

  1. 找到一个可以区分两个字符串的规则。在这种情况下,我首先确定字符串的一般“组”:以“m”、“p”、“s”结尾的东西、单个字母或以“d”结尾的东西。

  2. 如果该规则区分两个输入,则返回一个数字,如果 o1 应该先出现,则返回负数,如果 o1 应该后出现,则返回正数。要记住这个约定,请考虑“如果o1o2 是小整数,就像o1 - o2”(忽略溢出)。

  3. 如果该规则无法区分o1o2,则查找其他规则等。

  4. 最后,如果你的规则用完了,返回 0 或委托其他比较。

请记住,您的 Comparator 应该合理地处理您不期望的字符串 - 它可能会抛出异常(如果给它“Xs”,则会抛出异常),但如果它不抛出异常那么结果应该是一致的。也就是说,如果compare(x, y) &lt; 0compare(y, z) &lt; 0 则如果compare(x, z) 没有抛出异常,则compare(x, z) 必须为负数,而不管xyz 是什么。确保这一点的一种方法是按照我在此处所做的方式构建您的比较器,在其中我为每个字符串找到一系列“订单号”,然后如果订单号没有帮助,则委托给 String.compareTo

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-01-19
    • 1970-01-01
    • 2018-04-23
    • 1970-01-01
    • 1970-01-01
    • 2011-01-13
    • 2020-04-21
    相关资源
    最近更新 更多