在Java中,一个"decorate and sort"简洁的实现?
In Java, a "decorate and sort" concise implementation?
我是第一次学习 Java(我之前的经验是 Python 和 Haskell)。在 Python 中,我有一种情况需要 "decorate and sort" 习语。比如下面的(代码没有测试但是大致正确):
origList = <something>
decorated = sorted( [(evalFunc(item), item) for item in origList] )
finalList = [item for _, item in decorated]
通过选择不同的 evalFunc
,您可以选择排序方式。
在 Java 中,我正在编写一个程序,通过从音符列表中进行选择、评估每个音符的 "fitness" 并选择最佳音符来创作音乐。我有一个 class 代表音符:
class Note {
...
}
我有一个 class 将音符的适合度表示为两个值,即好和坏(是的,这些在我的程序中是不同的概念)。注意:在 Python 或 Haskell 中,这只是一个二元组,但我的理解是 Java 没有通常意义上的元组。我可以把它做成一对,但是像 List<Pair<Type1,Pair<Type2,Type3>>>
这样到处声明变量会变得笨拙。 (顺便说一句,我认为 Java 也没有类型别名,这可以让我缩短声明。)
class Fitness {
double goodness;
double badness;
}
评估适应度的函数需要访问Note以外的几条数据。我们会说它是 "Composition" class:
的一部分
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 中的几行代码来说,这是很多代码。有更好的方法吗?
编辑:
解决一些问题。
"You don't need to decorate."好吧,我的适应度计算非常昂贵,所以我想为每个音符计算一次,并保存结果以备后用。
"Store goodness/badness in Note."好坏不单是属性一个音符;它仅在上下文中有意义并且可以更改。因此,这是我添加仅在某些情况下才有意义的可变状态的建议,或者如果存在意外突变的错误,则完全错误。这很丑陋,但也许是 Java 的必备拐杖。
您可以使用流:
Function<Foo, Bar> func = ...
Comparator<Foo> comparator = ...
var list = ...
var sorted = list.stream()
.sorted(comparator)
.map(func)
.collect(Collectors.toList());
Java 显然包含一个 Collections.sort :: List -> Comparator -> List
可以为您做所有事情。不过,它会改变原始列表。
不幸的是,Java 的标准库不包括元组,甚至不包括普通的 Pair
;不过,Apache Commnons 库可以。
简而言之,您不需要 Java 中的修饰/取消修饰方法。
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));
继续你已有的
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);
我是第一次学习 Java(我之前的经验是 Python 和 Haskell)。在 Python 中,我有一种情况需要 "decorate and sort" 习语。比如下面的(代码没有测试但是大致正确):
origList = <something>
decorated = sorted( [(evalFunc(item), item) for item in origList] )
finalList = [item for _, item in decorated]
通过选择不同的 evalFunc
,您可以选择排序方式。
在 Java 中,我正在编写一个程序,通过从音符列表中进行选择、评估每个音符的 "fitness" 并选择最佳音符来创作音乐。我有一个 class 代表音符:
class Note {
...
}
我有一个 class 将音符的适合度表示为两个值,即好和坏(是的,这些在我的程序中是不同的概念)。注意:在 Python 或 Haskell 中,这只是一个二元组,但我的理解是 Java 没有通常意义上的元组。我可以把它做成一对,但是像 List<Pair<Type1,Pair<Type2,Type3>>>
这样到处声明变量会变得笨拙。 (顺便说一句,我认为 Java 也没有类型别名,这可以让我缩短声明。)
class Fitness {
double goodness;
double badness;
}
评估适应度的函数需要访问Note以外的几条数据。我们会说它是 "Composition" class:
的一部分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 中的几行代码来说,这是很多代码。有更好的方法吗?
编辑:
解决一些问题。
"You don't need to decorate."好吧,我的适应度计算非常昂贵,所以我想为每个音符计算一次,并保存结果以备后用。
"Store goodness/badness in Note."好坏不单是属性一个音符;它仅在上下文中有意义并且可以更改。因此,这是我添加仅在某些情况下才有意义的可变状态的建议,或者如果存在意外突变的错误,则完全错误。这很丑陋,但也许是 Java 的必备拐杖。
您可以使用流:
Function<Foo, Bar> func = ...
Comparator<Foo> comparator = ...
var list = ...
var sorted = list.stream()
.sorted(comparator)
.map(func)
.collect(Collectors.toList());
Java 显然包含一个 Collections.sort :: List -> Comparator -> List
可以为您做所有事情。不过,它会改变原始列表。
不幸的是,Java 的标准库不包括元组,甚至不包括普通的 Pair
;不过,Apache Commnons 库可以。
简而言之,您不需要 Java 中的修饰/取消修饰方法。
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));
继续你已有的
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);