有没有更好的方法来找到标记较小的最近的对象?
class Prop implements Comparable {
BigDecimal marker
String value
int compareTo(other) {
return marker <=> other.marker
}
}
def props = [new Prop(marker: 0G, value: "1st"),
new Prop(marker: 20G, value: "2nd"),
new Prop(marker: 30G, value: "3rd"),
new Prop(marker: 40G, value: "4th"),
new Prop(marker: 50G, value: "5th"),
new Prop(marker: 100G, value: "6th"),
new Prop(marker: 1000G, value: "7th")]
def whereAmI = 44G
def here = props.findAll{it.marker <= whereAmI}.max()
答案 0 :(得分:2)
编辑:已更新以返回正确的对象类型,并且为空。
假设订单无法保证,您可以使用the inject
method:
// Inject null, so if nothing is lower than max, this returns null
def here = props.inject(null){ max, it ->
(it.marker <= whereAmI && (!max || it > max)) ? it : max
}
如果列表总是排序,那么只需使用:
// Inject null, so if nothing is lower than max, this returns null
def here = props.inject(null){ max, it ->
(it.marker <= whereAmI) ? it : max
}
这里的好处是你只需要遍历集合一次,并且不会创建额外的临时List
较小的值。
现在,根据您的列表大小,参数可能是您的原始示例更容易阅读,并且更加清晰。代码清晰度可以超越性能。
(注意:inject
是Groovy的reduce or fold版本。)
答案 1 :(得分:0)
如果道具列表按标记排序,这是OverZealous注入解决方案的替代方案。在列表上创建takeWhile
方法,然后取最后一个小于whereAmI
的方法:
List.metaClass.takeWhile = { closure ->
def iter = delegate.iterator()
int i = 0
def n = iter.next()
while(closure.call(n)) {
i++
if (iter.hasNext())
n = iter.next()
else
break
}
return delegate[0..<i]
}
props.takeWhile { it.marker < whereAmI }[-1] // exception if nothing matches
props.takeWhile { it.marker < whereAmI }.reverse()[0] // null if nothing matches
答案 2 :(得分:0)
更好的方法是取决于你认为更好的方式。
为了代码可读性,我认为您最初提出的解决方案非常好。
OverZealous solution migth会更快,但正如他所提到的那样,它不具有可读性。事实上,如果性能对于该代码非常重要,那么您应该对其进行分析以确定它是否真的更快。
如果props
列表创建一次(或几次)但here
值计算多次,则您可以考虑对props
进行排序并查找whereAmI
二进制搜索。这将花费log(n)时间(n为props
的大小)而不是线性时间。
// Make whereAmI a Prop to avoid defining a Comparator
def whereAmI = new Prop(marker: 44G, value: '')
def i = Collections.binarySearch(props, whereAmI)
def here = props[i >= 0 ? i : -i - 2]
当whereAmI
不在props
时,bynarySearch
会返回1的负数加上whereAmI
所应的索引,因此看似神奇的-1 -2
警告:如果props
中没有小于whereAmI
的元素,则无效。如果这是一个可能的情况,你应该要求i == -1
。在这种情况下,原始代码已分配null
到here
:
def here = i == -1 ? null : props[i >= 0 ? i : -i - 2]