我第一次学习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的必要拐杖。
答案 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));