在Java中,"装饰和排序"简洁的实施?

时间:2018-06-06 21:38:37

标签: java comparator

我第一次学习Java(我之前的经验是Python和Haskell)。我有一种情况,在Python中,需要一个"装饰和排序"成语。如下所示(代码未经测试,但大致相同):

origList = <something>
decorated = sorted( [(evalFunc(item), item) for item in origList] )
finalList = [item for _, item in decorated]

通过选择不同的evalFunc,您可以选择如何排序。

在Java中,我正在编写一个程序,通过从一系列笔记中进行选择来编写音乐,评估&#34;健身&#34;每个音符,并选择最好的。我有一个代表音符的课程:

class Note {
   ...
}

我有一个类,它将一个音符的适应性表示为两个值,它的优点和缺点(是的,这些是我程序中的单独概念)。注意:在Python或Haskell中,这只是一个2元组,但我的理解是Java没有通常意义上的元组。我可以把它变成一对,但是在List<Pair<Type1,Pair<Type2,Type3>>>这样的地方声明变量变得笨拙。 (顺便说一句,我不认为Java也有类型别名,这会让我缩短声明。)

class Fitness {
    double goodness;
    double badness;
}

评估适应性的函数需要访问Note以外的几个数据。我们会说它是&#34; Composition&#34;的一部分。类:

class Composition {
    ... data declared here ... ;

    public Fitness evaluate(Note n) {
    }
}

我希望能够按数字顺序比较Fitness个对象。有两种比较方式:根据具体情况,可以在数值上比较好坏。

class CompareFitnessByGoodness implements Comparator<Fitness> {
}

class CompareFitnessByBadness implements Comparator<Fitness> {
}

我想将Note与其适应性打包在一起,因此我可以按照适应性对合并列表进行排序,然后提取最佳Note

class Together {
    public Note;
    public Fitness;
}

我希望通过善良或不良来对List<Together>进行排序。所以我可能需要:

class CompareTogetherByGoodness implements Comparator<Together> {
    ...
}

class CompareTogetherByBadness implements Comparator<Together> {
   ...
}

最终我会写一些类似

的内容
Note pickBest(List<Together> notes) {
    // Pick a note that's not too bad, and pretty good at the same 
    // time.

    // First sort in order of increasing badness, so I can choose
    // the bottom half for the next stage (i.e. the half "least bad"
    // notes).
    Collections.sort(notes, new CompareTogetherByBadness());
    List<Together> leastBadHalf = notes.subList(0, notes.size()/2);

    // Now sort `leastBadHalf` and take the last note: the one with
    // highest goodness.
    Collections.sort(leastBadHalf, new CompareTogetherByGoodness());

    return leastBadHalf.get(leastBadHalf.size()-1);
}

呼!对于Haskell或Python中的几行来说,这是很多代码。有更好的方法吗?

编辑:

解决一些问题。

&#34;你不需要装饰。&#34;好吧,我的健身计算非常昂贵,所以我想为每个音符计算一次,并保存结果以供以后访问。

&#34;将好/坏存储在Note中。&#34;善或恶不仅仅是笔记的属性;它只在上下文中有意义,并且可以改变。所以这是一个建议,我添加了一些只在某些情况下有意义的可变状态,或者如果有一个偶然会改变它的错误,那就是明显错误。这很难看,但也许是Java的必要拐杖。

4 个答案:

答案 0 :(得分:2)

按照你已有的方式继续

origList = <something>
decorated = sorted( [(evalFunc(item), item) for item in origList] )
finalList = [item for _, item in decorated]

这与现代Java相同:

给出你的作文对象:

Composition composer = ...;

以及笔记清单:

List<Note> notes = ...;

然后你可以这样做:

List<Together> notesAllTogetherNow = notes.stream()
                                          .map(note -> new Together(note, composer.evaluate(note)))
                                          .sorted(new CompareTogetherByGoodness())
                                          .collect(Collectors.toList());

为了获得最佳记录,您可以采取进一步措施:

Optional<Note> bestNote = notes.stream()
                               .map(note -> new Together(note, composer.evaluate(note)))
                               .sorted(new CompareTogetherByBadness())
                               .limit(notes.size() / 2) // Taking the top half
                               .sorted(new CompareTogetherByGoodness())
                               .findFirst() // Assuming the last comparator sorts in descending order
                               .map(Together::getNote);

答案 1 :(得分:1)

您可以使用流:

Function<Foo, Bar> func = ...
Comparator<Foo> comparator = ...
var list = ...
var sorted = list.stream()
                 .sorted(comparator)
                 .map(func)  
                 .collect(Collectors.toList());

答案 2 :(得分:1)

Java显然包含Collections.sort :: List -> Comparator -> List,可以为您完成所有事情。但它改变了原始列表。

不幸的是,Java的标准库不包含元组甚至是普通的Pair;但是,Apache Commnons库确实可以。

简而言之,您不需要 Java中的装饰/未装饰方法。

答案 3 :(得分:0)

class Fitness {
    double goodness;
    double badness;
}

class Together {
    Note note;
    Fitness fitness;
}

class Note{
}

    List<Together> notes = ...
    Collections.sort(notes, Comparator.comparingDouble(value -> value.fitness.badness));
    List<Together> leastBadHalf = notes.subList(0, notes.size()/2);
    return leastBadHalf.stream().max(Comparator.comparingDouble(value -> value.fitness.goodness));