按枚举值或字符串值

时间:2018-01-09 10:45:51

标签: java sorting arraylist java-8

我希望通过比较字符串值或枚举值,按升序和降序对ArrayList进行排序。

这是我要排序的ArrayList:

List<Issue> issues;

列表将根据我给函数的两个参数(fieldsort)进行排序:

private List<Issue> sortList(List<Issue> list, String field, String sort) {
    // My code goes here
}

因此,我们假设field值为titlesort值为DESC,那么我想按顺序排序列表中的所有Issue元素他们的title提交了,这就是我的尝试:

return list.stream().sorted((i1, i2) -> String.compare(i2.getTitle(), i1.getTitle())).collect(Collectors.toList());

但这会产生以下错误:

The method compare(String, String) is undefined for the type String

对于枚举,我无法弄清楚如何比较它们的值。

我该如何解决这个问题?

类定义:

问题

public class Issue {

    private IssueElementEnum issueElement;
    private IssueTypeEnum issueType;
    private String title;

    // Getters and setters
}

IssueElementEnum

public enum IssueElementEnum {
    PROFILE {

        @Override
        public String toString() {
            return "Profil";
        }
    }
    ROLE {

        @Override
        public String toString() {
            return "Rôle";
        }
    },
    User {

        @Override
        public String toString() {
            return "Utilisateur";
        }
    }
}

IssueTypeEnum

public enum IssueTypeEnum {
    PROFILE {

        @Override
        public String toString() {
            return "Sans Profil";
        }
    },
    ROLE {

        @Override
        public String toString() {
            return "Sans Rôle";
        }
    },
    USER {

        @Override
        public String toString() {
            return "Sans Utilisateur";
        }
    }
}

编辑:

有时我想用多个字段对列表进行排序,例如(按title按升序对列表进行排序,然后按issueElement.toSting()按降序排序,为此我创建了以下类:

public class SortDTO implements ISort {

    public static final String ASC = "ASC";
    public static final String DESC = "DESC";

    private String field;

    private String sort;


    public GridSortDTO() {
        this(null, null);
    }

    public GridSortDTO(final String field, final String sort) {
        super();
        this.field = field;
        this.sort = sort;
    }

    @Override
    public String getField() {
        return field;
    }

    @Override
    public void setField(final String field) {
        this.field = field;
    }

    @Override
    public String getSort() {
        return sort;
    }

    @Override
    public void setSort(final String type) {
        this.sort = type;
    }

    @Override
    public String toString() {
        return String.format("Sort[field=%s, sort=%s]", this.field, this.sort);
    }
}

public interface ISort {

    String getField();

    void setField(final String field);

    String getSort();

    void setSort(final String type);
}

然后我的排序信息存储在这个数组中:GridSortDTO[] sorts

因此,例如sorts将包含以下信息:

[{"field":"title","sort":"asc"},{"field":"issueElement","sort":"desc"}]

我该如何实现?

3 个答案:

答案 0 :(得分:4)

目前尚不清楚您希望enum类型,声明顺序(PROFILE, ROLE, USER)或其toString()表示的词典顺序。

在后一种情况下,您可以将方法实现为

private List<Issue> sortList(List<Issue> list, String field, String sort) {
    Function<Issue,String> f;
    switch(field) {
        case "Title": f = Issue::getTitle; break;
        case "IssueElement": f = i -> i.getIssueElement().toString(); break;
        case "IssueType": f = i -> i.getIssueType().toString(); break;
        default: throw new IllegalArgumentException("unknown property '"+field+"'");
    }
    Comparator<Issue> cmp = Comparator.comparing(f);
    if("DESC".equalsIgnoreCase(sort)) cmp = cmp.reversed();
    else if(!"ASC".equalsIgnoreCase(sort))
        throw new IllegalArgumentException("invalid sort '"+sort+"'");
    return list.stream().sorted(cmp).collect(Collectors.toList());
}

如果您想使用enum声明顺序,那么您的常用代码会略逊一筹:

private List<Issue> sortList(List<Issue> list, String field, String sort) {
    Comparator<Issue> cmp;
    switch(field) {
        case "Title": cmp = Comparator.comparing(Issue::getTitle); break;
        case "IssueElement": cmp = Comparator.comparing(Issue::getIssueElement); break;
        case "IssueType": cmp = Comparator.comparing(Issue::getIssueType); break;
        default: throw new IllegalArgumentException("unknown property '"+field+"'");
    }
    if("DESC".equalsIgnoreCase(sort)) cmp = cmp.reversed();
    else if(!"ASC".equalsIgnoreCase(sort))
        throw new IllegalArgumentException("invalid sort '"+sort+"'");
    return list.stream().sorted(cmp).collect(Collectors.toList());
}

您还可以维护现有订单的地图,而不是switch声明,从而提供更多灵活性:

// in Java 9, you should replace Arrays.asList(...) with List.of(...)
static final Map<List<String>,Comparator<Issue>> ORDER;
static {
    Map<List<String>,Comparator<Issue>> m = new HashMap<>();
    Comparator<Issue> c = Comparator.comparing(Issue::getTitle);
    m.put(Arrays.asList("Title", "asc"), c);
    m.put(Arrays.asList("Title", "desc"), c.reversed());
    c = Comparator.comparing(Issue::getIssueElement);
    m.put(Arrays.asList("IssueElement", "asc"), c);
    m.put(Arrays.asList("IssueElement", "desc"), c.reversed());
    c = Comparator.comparing(Issue::getIssueType);
    m.put(Arrays.asList("IssueType", "asc"), c);
    m.put(Arrays.asList("IssueType", "desc"), c.reversed());
    ORDER = Collections.unmodifiableMap(m);
}
private List<Issue> sortList(List<Issue> list, String field, String sort) {
    Comparator<Issue> cmp = ORDER.get(Arrays.asList(field, sort.toLowerCase(Locale.ROOT)));
    if(cmp == null)
        throw new IllegalArgumentException("property '"+field+"', sort '"+sort+"'");
    return list.stream().sorted(cmp).collect(Collectors.toList());
}

这种方法可以适应您的新要求,但我强烈建议稍作重新设计:

enum Direction { ASCENDING, DESCENDING }
public interface ISort {
    String getField();
    void setField(final String field);
    Direction getSort();
    void setSort(final Direction type);
}

调整实现是直截了当的,但是你应该避免允许null用于排序方向,因为它只是两个合法值中的任何一个:

public class SortDTO implements ISort {
    private String field;
    private Direction sort;
    public SortDTO() { this(null, Direction.ASCENDING); }
    public SortDTO(String field, Direction sort) {
        this.field = field;
        this.sort = sort;
    }
    public String getField() { return field; }
    public void setField(String field) { this.field = field; }
    public Direction getSort() { return sort; }
    public void setSort(Direction sort) { this.sort = Objects.requireNonNull(sort); }
    @Override
    public String toString() {
        return String.format("Sort[field=%s, sort=%s]", this.field, this.sort);
    }
}

我们使用不可变密钥类型扩充这些类型,这些密钥类型能够捕获ISort实现的当前状态并具有正确的equalshashCode实现:

final class SortKey {
    final String field;
    final Direction direction;
    private SortKey(String f, Direction d) { field=f; direction=d; }
    @Override
    public int hashCode() {
        return field.hashCode()*2+direction.ordinal();
    }
    @Override
    public boolean equals(Object obj) {
        if(this == obj) return true;
        if(!(obj instanceof SortKey)) return false;
        SortKey that = (SortKey)obj;
        return this.direction == that.direction && this.field.equals(that.field);
    }
    static SortKey of(String field, Direction dir) {
        return new SortKey(Objects.requireNonNull(field), Objects.requireNonNull(dir));
    }
    static SortKey of(ISort s) {
        return of(s.getField(), s.getSort());
    }
}

然后,适应的解决方案可能看起来像

static final Map<SortKey,Comparator<Issue>> ORDER;
static {
    Map<SortKey,Comparator<Issue>> m = new HashMap<>();
    Comparator<Issue> c = Comparator.comparing(Issue::getTitle);
    m.put(SortKey.of("Title", Direction.ASCENDING), c);
    m.put(SortKey.of("Title", Direction.DESCENDING), c.reversed());
    c = Comparator.comparing(Issue::getIssueElement);
    m.put(SortKey.of("IssueElement", Direction.ASCENDING), c);
    m.put(SortKey.of("IssueElement", Direction.DESCENDING), c.reversed());
    c = Comparator.comparing(Issue::getIssueType);
    m.put(SortKey.of("IssueType", Direction.ASCENDING), c);
    m.put(SortKey.of("IssueElement", Direction.DESCENDING), c.reversed());
    ORDER = Collections.unmodifiableMap(m);
}
private List<Issue> sortList(List<Issue> list, ISort... order) {
    if(order.length == 0) return new ArrayList<>(list);
    Comparator<Issue> cmp = ORDER.get(SortKey.of(order[0]));
    if(cmp == null) throw new IllegalArgumentException(order[0].toString());
    for(int ix = 1; ix < order.length; ix++) {
        Comparator<Issue> next = ORDER.get(SortKey.of(order[ix]));
        if(next == null) throw new IllegalArgumentException(order[ix].toString());
        cmp = cmp.thenComparing(next);
    }
    return list.stream().sorted(cmp).collect(Collectors.toList());
}

这允许任意数量的排序标准,第一个是主要订单,第二个是次要订单,依此类推。

答案 1 :(得分:2)

实际上,比较您尝试使用的两个字符串的方法是compareTo而不是compare,它是在Comparable接口中定义的。看看javadoc:https://docs.oracle.com/javase/7/docs/api/java/lang/String.html

答案 2 :(得分:2)

如果您想按title对列表进行排序,请使用以下内容:

stream().sorted(Comparator.comparing(Issue::getTitle)).collect(Collectors.toList())

请查看java-8 Comparator