繁体   English   中英

Java:按给定字符串属性的子字符串排序对象列表(模式 ITEM/LOC/YYYY/N)

[英]Java: sorting list of objects by substrings of a given String property (pattern ITEM/LOC/YYYY/N)

我有一个对象列表,我想通过 formNumber 属性对它们进行排序(升序和降序)。

FormNumber 始终是模式 ITEM/LOC/YYYY/N 的字符串,其中:

  • 项目是恒定的
  • LOC - 三个字母的位置快捷方式,例如。 纽约市、MIA、TOR
  • YYYY - 年
  • N——数字。 总是一个素数,所以不会发生 05 或 007 之类的事情

我想先按 YYYY 排序,然后如果等于 N,然后如果等于 LOC。

对象的数量可以是数百而不是数千。 最好/最有效的方法是什么?

首先,创建一个包装器 class:

class ObjWrapper implements Comparable<ObjWrapper> {
    private static final Pattern DELIM = Pattern.compile("/");

    Obj obj;
    String[] formNumberSplit;
    

    public ObjWrapper(Obj obj) {
        this.obj = obj;
        this.formNumberSplit = DELIM.split(obj.getFormNumber());
    }

    @Override
    public int compareTo(ObjWrapper another) {
        int compareYear = formNumberSplit[2].compareTo(another.formNumberSplit[2]);
        if (compareYear != 0) {
            return compareYear;
        }

        int compareN = Integer.compare(
            Integer.parseInt(formNumberSplit[3]),
            Integer.parseInt(another.formNumberSplit[3]));
        if (compareN != 0) {
            return compareN;
        }

        return formNumberSplit[1].compareTo(another.formNumberSplit[1]);
    }

    public Obj getObj() {
        return obj;
    }
}

它将进行拆分并帮助对我们的对象进行排序。 当然,代替Obj的是您的 class。 然后进行排序:

List<Obj> sortedObjs = objsList.stream()
    .map(ObjWrapper::new)
    .sorted()
    .map(ObjWrapper::getObj)
    .collect(Collectors.toList());

我会创建三个比较器并在排序时将它们链接在一起。 它使您的代码更具可读性和明显性。 此外,您可以根据需要在降序和升序之间灵活切换各个属性的排序

例子:

List<String> list = new ArrayList<>(); 
list.add("ITEM/NYC/2020/3");
list.add("ITEM/TOR/2018/13");
list.add("ITEM/MIA/2020/41");
list.add("ITEM/NYC/2018/7");
list.add("ITEM/MIA/2018/11");
list.add("ITEM/NYC/2020/17");
list.add("ITEM/NYC/2019/13");
list.add("ITEM/MIA/2019/3");
list.add("ITEM/TOR/2019/3");

Comparator<String> byYear = (y1,y2)-> 
        Integer.compare(Integer.parseInt(y1.split("/")[2]), Integer.parseInt(y2.split("/")[2]));

Comparator<String> byN = (n1,n2)-> 
        Integer.compare(Integer.parseInt(n1.split("/")[3]), Integer.parseInt(n2.split("/")[3]));

Comparator<String> byLoc = (loc1,loc2)-> loc1.split("/")[1].compareTo(loc2.split("/")[1]);

// sort by all asc
list.sort(byYear.thenComparing(byN).thenComparing(byLoc));
list.forEach(System.out::println);

// sort by year desc, then by n asc and loc desc
list.sort(byYear.reversed().thenComparing(byN).thenComparing(byLoc).reversed());

// combine them as you wish or exclude one if not necessary etc...

如果排序顺序是固定的并且将来不会改变,您也可以将它们组合成一个比较器

编辑

假设您有一个带有 formNumber 属性的 class Foo :

class Foo{    
    String formNumber;

    public String getFormNumber() {
        return formNumber;
    }        
}

和一个 foos 列表:

List<Foo> fooList = ....

然后将上面的内容更改为:

Comparator<Foo> byYear = (y1,y2)-> 
        Integer.compare(Integer.parseInt(y1.getFormNumber().split("/")[2]), 
                Integer.parseInt(y2.getFormNumber().split("/")[2]));

Comparator<Foo> byN = (n1,n2)-> 
        Integer.compare(Integer.parseInt(n1.getFormNumber().split("/")[3]), 
                Integer.parseInt(n2.getFormNumber().split("/")[3]));

Comparator<Foo> byLoc = (loc1,loc2)-> loc1.getFormNumber().split("/")[1]
        .compareTo(loc2.getFormNumber().split("/")[1]);

比较器的用法保持不变

fooList.sort(byYear.thenComparing(byN).thenComparing(byLoc));

暂无
暂无

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

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