创建另一个可迭代对象的可迭代组合

时间:2018-04-06 16:03:01

标签: java algorithm groovy

我需要创建一组可迭代对象的所有组合。 我在Groovy上有一些用于生成组合的代码:

private static List<Map> expandLensesPositions(Map entry) {
    def expandedPositions = []

    def entryCopy = entry.clone() as Map

    def sphFrom = entryCopy.remove("sphFrom") as BigDecimal
    def sphTo = entryCopy.remove("sphTo") as BigDecimal

    def cylFrom = entryCopy.remove("cylFrom") as BigDecimal
    def cylTo = entryCopy.remove("cylTo") as BigDecimal

    def addFrom = entryCopy.remove("addFrom") as BigDecimal
    def addTo = entryCopy.remove("addTo") as BigDecimal

    def diameter = entryCopy.remove("diameterFrom")

    for (def sph in generateSeries(sphFrom, sphTo)) {
        for (def cyl in generateSeries(cylFrom, cylTo)) {
            for (def add in generateSeries(addFrom, addTo)) {
                def expandedEntryProps = [dioptre:sph, diameter:diameter, cylinderDioptre:cyl, addidation:add]

                expandedPositions << entryCopy + expandedEntryProps
            }
        }
    }

    return expandedPositions
}

在此代码generateSeries(from, to)中返回Iterable<BigDecimal>个对象。在此实现中,结果存储在ArrayList expandedPositions中,但是这种方法对于大量结果元素是不可接受的。有没有办法为所有可迭代对象创建包装器并迭代所有组合?

1 个答案:

答案 0 :(得分:1)

在Groovy中,您可以使用GroovyCollections.combinations(Iterable collection)函数创建所有组合的列表,例如

[[0,1], [2,3], [4,5]].combinations()

创建以下组合列表:

[[0, 2, 4], [1, 2, 4], [0, 3, 4], [1, 3, 4], [0, 2, 5], [1, 2, 5], [0, 3, 5], [1, 3, 5]]

请考虑以下创建地图条目列表的示例:

def sph = [1,2,3,4,5]
def cyl = [6,7,8,9,10]
def add = [11,12,13,14,15]
def diameter = 0.0

def result = [sph, cyl, add].combinations().collect { row ->
    [dioptre: row[0], diameter: diameter, cylinderDioptre: row[1], addidation: row[2]]
}

result.each {
    println it
}

它创建的输出遵循(125种组合):

[dioptre:1, diameter:0.0, cylinderDioptre:6, addidation:11]
[dioptre:2, diameter:0.0, cylinderDioptre:6, addidation:11]
[dioptre:3, diameter:0.0, cylinderDioptre:6, addidation:11]
[dioptre:4, diameter:0.0, cylinderDioptre:6, addidation:11]
[dioptre:5, diameter:0.0, cylinderDioptre:6, addidation:11]
[dioptre:1, diameter:0.0, cylinderDioptre:7, addidation:11]
[dioptre:2, diameter:0.0, cylinderDioptre:7, addidation:11]
[dioptre:3, diameter:0.0, cylinderDioptre:7, addidation:11]
[dioptre:4, diameter:0.0, cylinderDioptre:7, addidation:11]
[dioptre:5, diameter:0.0, cylinderDioptre:7, addidation:11]
[dioptre:1, diameter:0.0, cylinderDioptre:8, addidation:11]
[dioptre:2, diameter:0.0, cylinderDioptre:8, addidation:11]
[dioptre:3, diameter:0.0, cylinderDioptre:8, addidation:11]
[dioptre:4, diameter:0.0, cylinderDioptre:8, addidation:11]
[dioptre:5, diameter:0.0, cylinderDioptre:8, addidation:11]
[dioptre:1, diameter:0.0, cylinderDioptre:9, addidation:11]
[dioptre:2, diameter:0.0, cylinderDioptre:9, addidation:11]
[dioptre:3, diameter:0.0, cylinderDioptre:9, addidation:11]
[dioptre:4, diameter:0.0, cylinderDioptre:9, addidation:11]
[dioptre:5, diameter:0.0, cylinderDioptre:9, addidation:11]
[dioptre:1, diameter:0.0, cylinderDioptre:10, addidation:11]
[dioptre:2, diameter:0.0, cylinderDioptre:10, addidation:11]
[dioptre:3, diameter:0.0, cylinderDioptre:10, addidation:11]
[dioptre:4, diameter:0.0, cylinderDioptre:10, addidation:11]
[dioptre:5, diameter:0.0, cylinderDioptre:10, addidation:11]
[dioptre:1, diameter:0.0, cylinderDioptre:6, addidation:12]
[dioptre:2, diameter:0.0, cylinderDioptre:6, addidation:12]
[dioptre:3, diameter:0.0, cylinderDioptre:6, addidation:12]
[dioptre:4, diameter:0.0, cylinderDioptre:6, addidation:12]
[dioptre:5, diameter:0.0, cylinderDioptre:6, addidation:12]
[dioptre:1, diameter:0.0, cylinderDioptre:7, addidation:12]
[dioptre:2, diameter:0.0, cylinderDioptre:7, addidation:12]
[dioptre:3, diameter:0.0, cylinderDioptre:7, addidation:12]
[dioptre:4, diameter:0.0, cylinderDioptre:7, addidation:12]
[dioptre:5, diameter:0.0, cylinderDioptre:7, addidation:12]
[dioptre:1, diameter:0.0, cylinderDioptre:8, addidation:12]
[dioptre:2, diameter:0.0, cylinderDioptre:8, addidation:12]
[dioptre:3, diameter:0.0, cylinderDioptre:8, addidation:12]
[dioptre:4, diameter:0.0, cylinderDioptre:8, addidation:12]
[dioptre:5, diameter:0.0, cylinderDioptre:8, addidation:12]
[dioptre:1, diameter:0.0, cylinderDioptre:9, addidation:12]
[dioptre:2, diameter:0.0, cylinderDioptre:9, addidation:12]
[dioptre:3, diameter:0.0, cylinderDioptre:9, addidation:12]
[dioptre:4, diameter:0.0, cylinderDioptre:9, addidation:12]
[dioptre:5, diameter:0.0, cylinderDioptre:9, addidation:12]
[dioptre:1, diameter:0.0, cylinderDioptre:10, addidation:12]
[dioptre:2, diameter:0.0, cylinderDioptre:10, addidation:12]
[dioptre:3, diameter:0.0, cylinderDioptre:10, addidation:12]
[dioptre:4, diameter:0.0, cylinderDioptre:10, addidation:12]
[dioptre:5, diameter:0.0, cylinderDioptre:10, addidation:12]
[dioptre:1, diameter:0.0, cylinderDioptre:6, addidation:13]
[dioptre:2, diameter:0.0, cylinderDioptre:6, addidation:13]
[dioptre:3, diameter:0.0, cylinderDioptre:6, addidation:13]
[dioptre:4, diameter:0.0, cylinderDioptre:6, addidation:13]
[dioptre:5, diameter:0.0, cylinderDioptre:6, addidation:13]
[dioptre:1, diameter:0.0, cylinderDioptre:7, addidation:13]
[dioptre:2, diameter:0.0, cylinderDioptre:7, addidation:13]
[dioptre:3, diameter:0.0, cylinderDioptre:7, addidation:13]
[dioptre:4, diameter:0.0, cylinderDioptre:7, addidation:13]
[dioptre:5, diameter:0.0, cylinderDioptre:7, addidation:13]
[dioptre:1, diameter:0.0, cylinderDioptre:8, addidation:13]
[dioptre:2, diameter:0.0, cylinderDioptre:8, addidation:13]
[dioptre:3, diameter:0.0, cylinderDioptre:8, addidation:13]
[dioptre:4, diameter:0.0, cylinderDioptre:8, addidation:13]
[dioptre:5, diameter:0.0, cylinderDioptre:8, addidation:13]
[dioptre:1, diameter:0.0, cylinderDioptre:9, addidation:13]
[dioptre:2, diameter:0.0, cylinderDioptre:9, addidation:13]
[dioptre:3, diameter:0.0, cylinderDioptre:9, addidation:13]
[dioptre:4, diameter:0.0, cylinderDioptre:9, addidation:13]
[dioptre:5, diameter:0.0, cylinderDioptre:9, addidation:13]
[dioptre:1, diameter:0.0, cylinderDioptre:10, addidation:13]
[dioptre:2, diameter:0.0, cylinderDioptre:10, addidation:13]
[dioptre:3, diameter:0.0, cylinderDioptre:10, addidation:13]
[dioptre:4, diameter:0.0, cylinderDioptre:10, addidation:13]
[dioptre:5, diameter:0.0, cylinderDioptre:10, addidation:13]
[dioptre:1, diameter:0.0, cylinderDioptre:6, addidation:14]
[dioptre:2, diameter:0.0, cylinderDioptre:6, addidation:14]
[dioptre:3, diameter:0.0, cylinderDioptre:6, addidation:14]
[dioptre:4, diameter:0.0, cylinderDioptre:6, addidation:14]
[dioptre:5, diameter:0.0, cylinderDioptre:6, addidation:14]
[dioptre:1, diameter:0.0, cylinderDioptre:7, addidation:14]
[dioptre:2, diameter:0.0, cylinderDioptre:7, addidation:14]
[dioptre:3, diameter:0.0, cylinderDioptre:7, addidation:14]
[dioptre:4, diameter:0.0, cylinderDioptre:7, addidation:14]
[dioptre:5, diameter:0.0, cylinderDioptre:7, addidation:14]
[dioptre:1, diameter:0.0, cylinderDioptre:8, addidation:14]
[dioptre:2, diameter:0.0, cylinderDioptre:8, addidation:14]
[dioptre:3, diameter:0.0, cylinderDioptre:8, addidation:14]
[dioptre:4, diameter:0.0, cylinderDioptre:8, addidation:14]
[dioptre:5, diameter:0.0, cylinderDioptre:8, addidation:14]
[dioptre:1, diameter:0.0, cylinderDioptre:9, addidation:14]
[dioptre:2, diameter:0.0, cylinderDioptre:9, addidation:14]
[dioptre:3, diameter:0.0, cylinderDioptre:9, addidation:14]
[dioptre:4, diameter:0.0, cylinderDioptre:9, addidation:14]
[dioptre:5, diameter:0.0, cylinderDioptre:9, addidation:14]
[dioptre:1, diameter:0.0, cylinderDioptre:10, addidation:14]
[dioptre:2, diameter:0.0, cylinderDioptre:10, addidation:14]
[dioptre:3, diameter:0.0, cylinderDioptre:10, addidation:14]
[dioptre:4, diameter:0.0, cylinderDioptre:10, addidation:14]
[dioptre:5, diameter:0.0, cylinderDioptre:10, addidation:14]
[dioptre:1, diameter:0.0, cylinderDioptre:6, addidation:15]
[dioptre:2, diameter:0.0, cylinderDioptre:6, addidation:15]
[dioptre:3, diameter:0.0, cylinderDioptre:6, addidation:15]
[dioptre:4, diameter:0.0, cylinderDioptre:6, addidation:15]
[dioptre:5, diameter:0.0, cylinderDioptre:6, addidation:15]
[dioptre:1, diameter:0.0, cylinderDioptre:7, addidation:15]
[dioptre:2, diameter:0.0, cylinderDioptre:7, addidation:15]
[dioptre:3, diameter:0.0, cylinderDioptre:7, addidation:15]
[dioptre:4, diameter:0.0, cylinderDioptre:7, addidation:15]
[dioptre:5, diameter:0.0, cylinderDioptre:7, addidation:15]
[dioptre:1, diameter:0.0, cylinderDioptre:8, addidation:15]
[dioptre:2, diameter:0.0, cylinderDioptre:8, addidation:15]
[dioptre:3, diameter:0.0, cylinderDioptre:8, addidation:15]
[dioptre:4, diameter:0.0, cylinderDioptre:8, addidation:15]
[dioptre:5, diameter:0.0, cylinderDioptre:8, addidation:15]
[dioptre:1, diameter:0.0, cylinderDioptre:9, addidation:15]
[dioptre:2, diameter:0.0, cylinderDioptre:9, addidation:15]
[dioptre:3, diameter:0.0, cylinderDioptre:9, addidation:15]
[dioptre:4, diameter:0.0, cylinderDioptre:9, addidation:15]
[dioptre:5, diameter:0.0, cylinderDioptre:9, addidation:15]
[dioptre:1, diameter:0.0, cylinderDioptre:10, addidation:15]
[dioptre:2, diameter:0.0, cylinderDioptre:10, addidation:15]
[dioptre:3, diameter:0.0, cylinderDioptre:10, addidation:15]
[dioptre:4, diameter:0.0, cylinderDioptre:10, addidation:15]
[dioptre:5, diameter:0.0, cylinderDioptre:10, addidation:15]

我猜这个最终列表并不完全符合您的预期,因为在您的示例中,您将元素推送到最终列表

 expandedPositions << entryCopy + expandedEntryProps

但做这样的事情:

def result = [sph, cyl, add].combinations().collect { row ->
    entryCopy + [dioptre: row[0], diameter: diameter, cylinderDioptre: row[1], addidation: row[2]]
}

应该这样做。

懒洋洋地创建组合

正如您在下面的评论中所提到的,GroovyCollections.combinations(iterable)会创建一个列表并将所有组合存储在其中。如果您希望以更懒惰的方式创建组合,可以考虑使用自定义Iterator来计算特定迭代步骤的组合。请考虑以下示例:

final class LazyCombinationsIterator<T> implements Iterator<List<T>> {
    final AtomicInteger idx = new AtomicInteger(0)
    final List<List<T>> lists = []
    final int size
    final List<Integer> listCycle

    LazyCombinationsIterator(List<T>... lists) {
        this.lists.addAll(lists)

        this.size = (int) lists.inject(1) { acc, list -> acc * list.size() }

        this.listCycle = [1] + (lists.inject([]) { List<Integer> acc, list ->
            acc << (acc.isEmpty() ? list.size() : acc.last() * list.size())
        } as List)
    }

    @Override
    boolean hasNext() {
        return idx.get() < size
    }

    @Override
    List<T> next() {
        final int i = idx.getAndIncrement()
        final int to = lists.size()

        return (0..<(to)).collect {
            final List<T> list = lists.get(it)
            final int listIdx = (int) (i / listCycle.get(it))
            return list.get(listIdx % list.size())
        }
    }
}

此自定义迭代器至少需要两个类型为T的列表,并在迭代时生成计算。它创建与GroovyCollections.combinations(iterable)函数相同的输出,但它会懒惰地执行。

示例1:

new LazyCombinationsIterator<>([1, 2], [3, 4, 5], [6, 9]).each {
    println it
}

它创建以下输出:

[1, 3, 6]
[2, 3, 6]
[1, 4, 6]
[2, 4, 6]
[1, 5, 6]
[2, 5, 6]
[1, 3, 9]
[2, 3, 9]
[1, 4, 9]
[2, 4, 9]
[1, 5, 9]
[2, 5, 9]

示例2:

new LazyCombinationsIterator<>(['a', 'b'], ['c'], ['d', 'e']).each {
    println it
}

它创建以下输出:

[a, c, d]
[b, c, d]
[a, c, e]
[b, c, e]