Home > Enterprise >  Terraform: How to get all combinations of elements from a single list
Terraform: How to get all combinations of elements from a single list

Time:07-22

I am trying to get all combinations of a single terraform list (order doesn't matter). Whenever I google this I get results like setproduct, which can only return all combinations of 2 lists. However, I do not want to do this for 2 lists, I only want to do it for one single list. Sorry if this is a silly question, very new to Terraform and I can't find anything about this type of thing in the docs.

Example:

fruits = tolist(["Apple", "Banana", "Orange"])

Lets say I want every possible combination of 2 elements from this list (I'd also like this number to be able to be modified, so I can get all combinations of 1 element, or 3, etc.). So, I want every possible combination of 2 elements, like the following output:

[
    [
      "Apple",
      "Banana"
    ],
    [
      "Apple",
      "Orange"
    ],
    [
      "Orange",
      "Banana"
    ]
]

Is this sort of thing possible in Terraform language?

CodePudding user response:

How about this:

locals {
  fruits = ["Apple", "Banana", "Orange"]
  subset = 2
  permutations = flatten([for i in range(0, local.subset - 1):
      setproduct(tolist(element(local.fruits, i)), slice(local.fruits, i   1))
    ]
  )
}

Iterate over i, take the i element in the 'fruits' list and turn it into a list. Then remove all elements in the 'fruits' list up to (and including) the i'th element using the slice() command. Then create a set product using setproduct() function. Now increase i by 1, move to the next element in the 'fruits' list and repeat. Note that in each iteration the second list being passed to setproduct() is shorter than the previous one and so no duplicates occur.

Hope this helps!

CodePudding user response:

I think there are a few different ways to wrangle this using the primitives in Terraform. When I'm working with set-ish things I prefer to use the set primitives as much as possible, so here's one way to do that which uses sets as much as possible:

locals {
  fruits = toset(["Apple", "Banana", "Orange"])

  pairs = setproduct(local.fruits, local.fruits)

  permutations = toset([
    for p in local.pairs : toset(p)
    if p[0] != p[1]
  ])
}

The results for each of these local values are as follows:

fruits = toset([
  "Apple",
  "Banana",
  "Orange",
])

pairs = toset([
  [
    "Apple",
    "Apple",
  ],
  [
    "Apple",
    "Banana",
  ],
  [
    "Apple",
    "Orange",
  ],
  [
    "Banana",
    "Apple",
  ],
  [
    "Banana",
    "Banana",
  ],
  [
    "Banana",
    "Orange",
  ],
  [
    "Orange",
    "Apple",
  ],
  [
    "Orange",
    "Banana",
  ],
  [
    "Orange",
    "Orange",
  ],
])

permutations = toset([
  toset([
    "Apple",
    "Banana",
  ]),
  toset([
    "Apple",
    "Orange",
  ]),
  toset([
    "Banana",
    "Orange",
  ]),
])

The "trick" here is to turn the final pairs into sets and also make a set of those pairs, which conveniently discards all of the pairings that differ only in the order of the items, such as ["Apple", "Orange"] vs ["Orange", "Apple"].

This is technically not exactly what you asked for since the result is a set of sets rather than a list of lists. I can't think of any meaningful fixed order for the overall set of pairs to be in, but you could potentially sort the pairs themselves into alphabetical order if that's important to your outcome, with one additional step:

locals {
  sorted_permitations = toset([
    for p in local.permutations : sort(p)
  ])
}
sorted_permutations = toset([
  tolist([
    "Apple",
    "Banana",
  ]),
  tolist([
    "Apple",
    "Orange",
  ]),
  tolist([
    "Banana",
    "Orange",
  ]),
])
  • Related