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

huangapple go评论89阅读模式
英文:

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

问题

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

FormNumber始终是一个字符串,遵循以下模式:ITEM/LOC/YYYY/N,其中:

  • ITEM是常数
  • LOC是三个字母的位置缩写,例如NYC,MIA,TOR
  • YYYY是年份
  • N是数字,始终是质数,所以不会出现像05或007这样的情况

我想首先按YYYY排序,然后如果相等按N排序,最后如果还相等按LOC排序。

对象的数量可能会达到数百,而不是数千。最好/最有效的做法是什么?

英文:

I have a list of objects and I want to sort them (ascending and descending order) by a formNumber property.

FormNumber is always a String of a pattern ITEM/LOC/YYYY/N, where:

  • ITEM is constant
  • LOC - three-letter location shortcut, ex. NYC, MIA, TOR
  • YYYY - year
  • N - number. Always a prime number, so something like 05 or 007 won't happen

I want to sort first by a YYYY, then if equal by N, then if equal by LOC.

The number of objects can go in hundreds rather than thousands. What will be the best / most efficient way of doing this?

答案1

得分: 0

以下是您要翻译的代码部分:

首先创建一个包装类

    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` 部分应替换为您的类名然后进行排序

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

希望这对您有帮助。

英文:

First, create a wrapper class:

class ObjWrapper implements Comparable&lt;ObjWrapper&gt; {
private static final Pattern DELIM = Pattern.compile(&quot;/&quot;);
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;
}
}

It will do the splitting and will help sorting our objects. Of course, instead of Obj is your class. Then do the sorting:

List&lt;Obj&gt; sortedObjs = objsList.stream()
.map(ObjWrapper::new)
.sorted()
.map(ObjWrapper::getObj)
.collect(Collectors.toList());

答案2

得分: 0

我将以下内容翻译成中文:

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

示例:

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

// 按所有属性升序排序
list.sort(byYear.thenComparing(byN).thenComparing(byLoc));
list.forEach(System.out::println);

// 按年份降序,然后按n升序和loc降序排序
list.sort(byYear.reversed().thenComparing(byN).thenComparing(byLoc).reversed());

// 根据需要组合它们或者如果不必要的话可以排除其中一个等...

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

编辑

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

class Foo{    
    String formNumber;

    public String getFormNumber() {
        return formNumber;
    }        
}

以及一个Foo对象的列表:

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));
英文:

I would create three comparators and chain them together when sorting. It makes your code more readable and obvious. Also, you can flexibly switch the sorting of the individual attributes between descending and ascending as needed

Example:

List&lt;String&gt; list = new ArrayList&lt;&gt;(); 
list.add(&quot;ITEM/NYC/2020/3&quot;);
list.add(&quot;ITEM/TOR/2018/13&quot;);
list.add(&quot;ITEM/MIA/2020/41&quot;);
list.add(&quot;ITEM/NYC/2018/7&quot;);
list.add(&quot;ITEM/MIA/2018/11&quot;);
list.add(&quot;ITEM/NYC/2020/17&quot;);
list.add(&quot;ITEM/NYC/2019/13&quot;);
list.add(&quot;ITEM/MIA/2019/3&quot;);
list.add(&quot;ITEM/TOR/2019/3&quot;);
Comparator&lt;String&gt; byYear = (y1,y2)-&gt; 
Integer.compare(Integer.parseInt(y1.split(&quot;/&quot;)[2]), Integer.parseInt(y2.split(&quot;/&quot;)[2]));
Comparator&lt;String&gt; byN = (n1,n2)-&gt; 
Integer.compare(Integer.parseInt(n1.split(&quot;/&quot;)[3]), Integer.parseInt(n2.split(&quot;/&quot;)[3]));
Comparator&lt;String&gt; byLoc = (loc1,loc2)-&gt; loc1.split(&quot;/&quot;)[1].compareTo(loc2.split(&quot;/&quot;)[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...

You can also combine them into one comparator if the sort order is fixed and will not change in the future

EDIT

Assuming you have a class Foo with a formNumber property:

class Foo{    
String formNumber;
public String getFormNumber() {
return formNumber;
}        
}

and a list of foos:

List&lt;Foo&gt; fooList = ....

then change the above to something like :

Comparator&lt;Foo&gt; byYear = (y1,y2)-&gt; 
Integer.compare(Integer.parseInt(y1.getFormNumber().split(&quot;/&quot;)[2]), 
Integer.parseInt(y2.getFormNumber().split(&quot;/&quot;)[2]));
Comparator&lt;Foo&gt; byN = (n1,n2)-&gt; 
Integer.compare(Integer.parseInt(n1.getFormNumber().split(&quot;/&quot;)[3]), 
Integer.parseInt(n2.getFormNumber().split(&quot;/&quot;)[3]));
Comparator&lt;Foo&gt; byLoc = (loc1,loc2)-&gt; loc1.getFormNumber().split(&quot;/&quot;)[1]
.compareTo(loc2.getFormNumber().split(&quot;/&quot;)[1]);

the usage of the comparators remains the same

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

huangapple
  • 本文由 发表于 2020年7月22日 18:20:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/63032019.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定