简体   繁体   English

Java-字符串的自定义排序ArrayList

[英]Java - Custom Sort ArrayList of Strings

I want to sort an ArrayList of strings of length 1 or 2 in a specific order. 我想按特定顺序对长度为1或2的字符串的ArrayList进行排序。

the order is 订单是

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

if you get the idea? 如果你有主意?

For example, the ArrayList is; 例如,ArrayList是;

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

I am trying to write a method in the class where this ArrayList is a field that will put it in the desired order. 我正在尝试在该ArrayList是将其按所需顺序放置的字段的类中编写一个方法。

Questions similar point to comparators, but I've found every explanation very confusing, but doing something different than I want anyway. 相似的问题指向比较器,但是我发现每个解释都非常混乱,但是无论如何我做的都不一样。

Id be perfectly fine with just writing the order out completely. 只需完全将订单写完即可,Id非常好。

Since I advocated to reopen this, here's a Comparator<String> that will do what you want: 由于我主张重新打开它,因此下面的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);
  }
}

It can be used as: 它可以用作:

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

This produces: 这将产生:

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]

The general strategy here is: 这里的一般策略是:

  1. find a rule that might distinguish between two strings. 找到可以区分两个字符串的规则。 In this case, I first identify the general "group" of the string: things that end in "m", in "p", in "s", that are single letters, or that end in "d". 在这种情况下,我首先确定字符串的一般“组”:以“ m”,“ p”,“ s”结尾,单个字母或以“ d”结尾的事物。

  2. If that rule distinguishes the two inputs, return a number that is negative if o1 should come first, and positive if o1 should come later. 如果该规则将两个输入区分开,则如果o1首先出现,则返回负数,如果o1随后出现,则返回正数。 To remember this convention, think "it's like o1 - o2 if o1 and o2 are small integers" (ignoring overflow). 为了记住这一约定,请考虑“如果o1o2是小整数,则就像o1 - o2 ”(忽略溢出)。

  3. If that rule doesn't distinguish o1 and o2 , find another rule, etc. 如果该规则不能区分o1o2 ,请找到另一个规则, o1 o2

  4. Finally, if you run out of rules, return 0 or delegate to some other comparison. 最后,如果您用完规则,则返回0或委托其他比较。

Remember in this that your Comparator should reasonably handle strings that you don't expect - it can throw an exception (as this one will if you give it "Xs"), but if it doesn't throw an exception then the result should be consistent. 请记住,您的Comparator应该合理地处理您不期望的字符串-它可以引发异常(因为如果您给它赋予“ Xs”,它将引发异常),但是如果它不引发异常,则结果应为一致的。 That is, if compare(x, y) < 0 and compare(y, z) < 0 then if compare(x, z) doesn't throw an exception, compare(x, z) must be negative, regardless of what x , y , and z are. 也就是说,如果compare(x, y) < 0compare(y, z) < 0则如果compare(x, z)没有引发异常,则不管x是什么, compare(x, z)必须为负。 , yz为。 One way to ensure that is to structure your comparator the way I did here, where I find a series of "order numbers" for each string and then delegate to String.compareTo if the order numbers are no help. 确保比较器的一种方法是按照我在此处所做的方式构造比较器,在该方法中,我为每个字符串找到一系列“订单号”,然后如果订单号无济于事,则委托给String.compareTo

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM