acsadam0404
acsadam0404

Reputation: 2831

groovy way to pair each element in a list

Every element should be paired with each other but only once.

Given a list A, B, C I want to make the following list of pairs: (A,B), (A,C), (B,C)

Similarly for 4 elements A, B, C, D the result should be (A,B), (A,C), (A,D), (B,C), (B,D), (C,D).

I tried with eachPermutation, eachCombintation but couldn't find a nice way. It would be a big help if you would tell me what's the matemathical name for this operation.

Upvotes: 2

Views: 1889

Answers (5)

dcasleton
dcasleton

Reputation: 56

A little late but seems subsequences would solve this quickly. It provides more than pairs, but limiting the result set would be trivial and obvious to readers in the future:

def pairs(def l) {
  l.subsequences().findAll {it.size() == 2}
}
assert pairs(['a','b','c']) == [['a','b'], ['a','c'], ['b', 'c']] as Set
assert pairs(['a', 'b', 'c', 'd']) == [['a', 'b'], ['a', 'c'], ['a', 'd'], ['b', 'c'], ['b', 'd'], ['c', 'd']] as Set

Upvotes: 4

dmahapatro
dmahapatro

Reputation: 50265

With eachCombination it would be:

def l = ['A', 'B', 'C', 'D'], result = []

[l, l].eachCombination {
    if ( ! ( it in result*.intersect( it ) || it[0] == it[1] ) ) {
        result << it.reverse()
    }
}

assert result == [
    ['A', 'B'], ['A', 'C'], ['A', 'D'], ['B', 'C'], ['B', 'D'], ['C', 'D']
] 

Upvotes: 1

Paweł Piecyk
Paweł Piecyk

Reputation: 2789

There's probably no such a feature in Groovy, but you can implement it quite easily:

def pairs(def elements) {
    return elements.tail().collect { [elements.head(), it] } + (elements.size() > 1 ? pairs(elements.tail()) : [])
}

assert pairs(['A', 'B', 'C']) == [['A', 'B'], ['A', 'C'], ['B', 'C']]
assert pairs(['A', 'B', 'C', 'D']) == [['A', 'B'], ['A', 'C'], ['A', 'D'], ['B', 'C'], ['B', 'D'], ['C', 'D']]

Upvotes: 4

Will
Will

Reputation: 14539

You can use a combinations, toSet, sort and findAll the remaining whose size equals 2:

def uniqueCombinations = { l ->
  [l,l].combinations()*.toSet()*.sort().unique().findAll { it.size() == 2 }
}

l=[1,2,3]
assert uniqueCombinations(l) == [[1, 2], [1, 3], [2, 3]]

Upvotes: 3

cfrick
cfrick

Reputation: 37063

how about doing it recursive? combinnations of the first element and the tail and then recurse on the rest of the list.

def comb(l,r=[]) {
    if (l) {
        r.addAll( [l.head(), l.tail()].combinations() )
        return comb(l.tail(), r)
    }
    return r
}

def m = ['a','b','c','d']
def result = comb(m)
assert result == [['a', 'b'], ['a', 'c'], ['a', 'd'], ['b', 'c'], ['b', 'd'], ['c', 'd']]

Upvotes: 0

Related Questions