【问题标题】:Java Comparator sorting order [duplicate]Java比较器排序顺序[重复]
【发布时间】:2014-05-20 07:07:27
【问题描述】:

我正在使用 Java Comparator 根据该对象中的某个值对我的对象之一进行排序,如下所示:

@Override
public int compare(Event e1, Event e2) {
   if(sortOrder.equalsIgnoreCase(DESCENDING))
       return compareTo(e2, e1);
   else
       return compareTo(e1, e2);
}

public int compareTo(Event e1, Event e2) {
     Tag t1 = getTag(e1, tagName, tagType); 
     Tag t2 = getTag(e2, tagName, tagType);

     if(t1!=null && t2!=null){
        if(t1.getRank()==null && t2.getRank()!=null)
            return 1;
        else if(t2.getRank()==null && t1.getRank()!=null)
            return -1;          
        else if (t1.getRank() < t2.getRank())
            return -1;
        else if (t1.getRank() > t2.getRank())
            return 1;
        else
            return e1.getId().compareTo(e2.getId()); //If rank null or equal compute rank based on id.
     }
     return 0;
}

Tag getTag(Event e, String tagName, TagTypeEnum tagType){
    List<Tag> tags = e.getTags();
    for(CTagsDO tag: tags){
        if((tag.getType().getId() == tagType.getId()) && (tag.getName().equals(tagName)))
            return tag;
    }
    return null;
} 

在这里,我比较了来自 2 个事件的 2 个标签,这些标签具有一定的排名值。我根据标签对象中的这个排名对我的事件进行排序。

升序排列效果很好,它将排名值最低的事件放在排名较高的事件之后,并将排名值为空的所有事件放在最后。

但是对于 DESCENDING 顺序,由于我只是做一个倒置的 ASCENDING 顺序,它将所有排名为空的事件放在顶部,然后从排名最高的事件开始,然后移动到最低排名。

在 DESCENDING 排序中,如何先获取排名最高的事件,然后是排名较低的事件,最后排名为空的事件?

【问题讨论】:

  • 只按一种顺序排序(比如升序),然后调用 Collections.reverse() 会将其更改为降序。不要重新发明轮子:)
  • 我可以建议你使用 Guava 来构建你的 Comparator 吗?它的订购设施非常好。 code.google.com/p/guava-libraries/wiki/OrderingExplained 它包括漂亮的 nullsFirstnullsLast 方法。
  • @WhoAmI - 这正是 OP 所说的他们不想要的。

标签: java sorting comparator comparable


【解决方案1】:

您需要在compareTo 中使用sortOrder.equalsIgnoreCase(DESCENDING)

@Override
public int compare(Event e1, Event e2) {
   if(sortOrder.equalsIgnoreCase(DESCENDING))
       return compareTo(e2, e1);
   else
       return compareTo(e1, e2);
}

public int compareTo(Event e1, Event e2) {
     Tag t1 = getTag(e1, tagName, tagType); 
     Tag t2 = getTag(e2, tagName, tagType);

     if(t1!=null && t2!=null){
        if(t1.getRank()==null && t2.getRank()!=null)
            return sortOrder.equalsIgnoreCase(DESCENDING) ? 1 : -1;
        else if(t2.getRank()==null && t1.getRank()!=null)
            return sortOrder.equalsIgnoreCase(DESCENDING) ? -1 : 1;          
        else if (t1.getRank() < t2.getRank())
            return -1;
        else if (t1.getRank() > t2.getRank())
            return 1;
        else
            return e1.getId().compareTo(e2.getId()); //If rank null or equal compute rank based on id.
     }
     return 0;
}

【讨论】:

  • 这将起作用,只是前 2 个 IF 条件中的数字应交换。谢谢。
【解决方案2】:

从您对它们进行的比较来看,我假设 rankid 字段是 Integer 对象。如果是这种情况,您可以在单独的比较器中执行空值检查,并使用它根据对象中的元素对对象进行排序。

我通过仅使用带有 rankid 元素的 Tag 类稍微简化了您的场景。

所以抽象的空检查比较器看起来像这样:(我在这里也包括了排序方面。)

public class NullsLastOrderedComparator<T extends Comparable<T>> implements Comparator<T>{

    public static final String ASCENDING = "ASCENDING";
    public static final String DESCENDING = "DESCENDING";

    private String sortOrder;

    public NullsLastOrderedComparator() {
        this(ASCENDING);
    }

    public NullsLastOrderedComparator(final String sortOrder) {
        this.sortOrder = sortOrder;
    }

    public int compare(final T o1, final T o2) {
        if( o1 == null && o2 == null) {
            return 0;
        }

        if( o1 == null ) {
            return 1;
        }

        if( o2 == null ) {
            return -1;
        }

        if(this.sortOrder.equalsIgnoreCase(DESCENDING)) {
            return o2.compareTo(o1);
        }

        return o1.compareTo(o2);
    }
}

然后可以在您要订购的类的比较器中使用它。您可以通过检查初始结果是否为 0 并在该点按第二个元素排序来包含要排序的两个元素。所以这里有一个例子TagComparator类:

public class TagComparator implements Comparator<Tag>{

    public static final String ASCENDING = "ASCENDING";
    public static final String DESCENDING = "DESCENDING";

    private String sortOrder;

    public TagComparator() {
        this(ASCENDING);
    }

    public TagComparator(final String sortOrder) {
        this.sortOrder = sortOrder;
    }

    public int compare(final Tag o1, final Tag o2) {
        final Comparator<Integer> comparator = new NullsLastOrderedComparator<Integer>(this.sortOrder);
        final int rankCompare = comparator.compare( o1.getRank(), o2.getRank() );

        if( rankCompare == 0 ) {
            return comparator.compare( o1.getId(), o2.getId() );
        }

        return compare;
    }
}

那么我的标签类是这样的:

public class Tag {

    private Integer rank;
    private Integer id;

    public Tag(final Integer rank, final Integer id) {
        this.rank = rank;
        this.id = id;
    }

    public Integer getRank() {
        return this.rank;
    }

    public void setRank(final Integer rank) {
        this.rank = rank;
    }

    public Integer getId() {
        return this.id;
    }

    public void setId(final Integer id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "R=" + this.rank + "&I=" + this.id; //Tag: " + super.toString() + "
    }

    public static void main(final String[] args) {
        final List<Tag> tags = new ArrayList<Tag>();
        tags.add(new Tag(null, 1));
        tags.add(new Tag(1, 2));
        tags.add(new Tag(null, 2));
        tags.add(new Tag(6, 5));
        tags.add(new Tag(null, 4));
        tags.add(new Tag(6, 3));
        tags.add(new Tag(null, 3));
        tags.add(new Tag(3, 7));

        System.out.println("ASCENDING");
        Collections.sort(tags, new TagComparator(TagComparator.ASCENDING));
        System.out.println(tags);

        System.out.println("DESCENDING");
        Collections.sort(tags, new TagComparator(TagComparator.DESCENDING));
        System.out.println(tags);
    }
}

输出是这样的:

升序 [R=1&I=2, R=3&I=7, R=6&I=3, R=6&I=5, R=null&I=1, R=null&I=2, R=null&I=4, R=null&I=6] 降序 [R=6&I=5, R=6&I=3, R=3&I=7, R=1&I=2, R=null&I=6, R=null&I=4, R=null&I=2, R=null&I=1]

【讨论】:

  • 我喜欢这种方法,但我也想处理等级具有相等值的事件(null 或相同的值)。我想处理它的原因是因为我在应用排序后进行分页,并且数据库不保证每次返回的事件的顺序。因此,当我找到相等的值时,我会根据它们的 id 对事件进行排序。
  • Rightio,这是可行的,我已经对我的答案进行了相当多的编辑。阅读为这个问题标记的重复问题并将其应用于您的场景,我使用了空检查比较器并在那里添加了排序可能性,然后在 Tag 类的比较器中使用它并包括了 rank 和 id 字段在那之内。您将在输出中看到相等的等级按 Id 以相同的顺序排列,但如果您愿意,您可以随时更改顺序。我还假设 id 是一个整数,但它同样适用于任何实现 Comparable 的对象。
【解决方案3】:

在检查sortOrder 的逻辑之前,在compare 中执行空检查。然后,只有在知道两个对象都不是null 时才调用compareTo

【讨论】:

    猜你喜欢
    • 2017-02-14
    • 2014-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-03
    • 1970-01-01
    • 1970-01-01
    • 2014-12-21
    相关资源
    最近更新 更多