有没有办法将Groovy的collect方法与另一个迭代器函数结合使用?

时间:2011-12-26 21:33:33

标签: groovy iterator

例如,groovy File类有一个很好的迭代器,它只会过滤目录而不是文件:

void eachDir(Closure closure) 

当我使用eachDir时,我必须先使用详细的方法创建集合并附加到它:

def collection = []    
dir1.eachDir { dir ->
  collection << dir
}

任何方式让它回到漂亮的紧凑收集语法?

2 个答案:

答案 0 :(得分:3)

我不知道这样做的任何“惯用”方式,很好的谜语! = d

您可以尝试将eachDir或任何类似函数传递给将收集其迭代的函数:

def collectIterations(fn) {
    def col = []
    fn {
        col << it
    }
    col
}

现在您可以将其用作:

def dir = new File('/path/to/some/dir')
def subDirs = collectIterations(dir.&eachDir)

def file = new File('/path/to/some/file')
def lines = collectIterations(file.&eachLine) 

(最后一个例子相当于file.readLines()

只有奖励积分,您可以将此功能定义为Closure类中的方法:

Closure.metaClass.collectIterations = {->
    def col = []
    delegate.call {
        col << it
    }
    col
}

def dir = new File('/path/to/some/dir')
def subDirs = dir.&eachDir.collectIterations()

def file = new File('/path/to/some/file')
def lines = file.&eachLine.collectIterations()

更新:另一方面,您可能也会这样做:

def col = []    
someDir.eachDir col.&add

我认为这个问题相当复杂,但并没有按照您的要求利用collect方法:)

答案 1 :(得分:1)

不是您所谈论的具体示例。 File.eachDir是一种奇怪的实现IMO。如果他们在File上实现iterator()以便你可以use the normal iterator methods在它们上而不是只执行闭包的自定义构建的那个就好了。

最简单的方法是获得一个干净的单行程,以满足您的需求,使用listFiles代替findAll:

dir1.listFiles().findAll { it.directory }

如果你看一下eachDir的实现,你会发现它正在做这个(并且你不关心这个实例的更多内容)。

对于许多类似的情况,inject是您正在寻找的方法,以便在迭代集合时更改起始值:

def sum = [1, 2, 3, 4, 5].inject(0) { total, elem -> total + elem }
assert 15 == sum