基于成员属性查找最大匹配列表成员的Groovy方法

时间:2011-09-23 21:18:04

标签: groovy

有没有更好的方法来找到标记较小的最近的对象?

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()

3 个答案:

答案 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。在这种情况下,原始代码已分配nullhere

def here = i == -1 ? null : props[i >= 0 ? i : -i - 2]