Join a map of lists with a list to create a map of lists with added values

I am wondering that given the following vars, would it be possible to create a map of lists

variable “subnets” {
type = list(object())
default [
{
name = “subnet1”
cidr_block = “10.0.1.0/24”
},
{
name = “subnet2”
cidr_block = “10.0.2.0/24”
},
]

variable “zones” {
type = list(string)
default = [“zone1”, “zone2”]
}

so this would leave me with something like:

variable "subnets_mapped" {
{
   name = "subnet1"
   cidr_block = "10.0.1.0/24"
   zone = zone1
},
{
   name = "subnet1"
   cidr_block = "10.0.1.0/24"
   zone = zone2
},
{
   name = "subnet2"
   cidr_block = "10.0.2.0/24"
   zone = zone1
},
{
   name = "subnet2"
   cidr_block = "10.0.2.1/24"
  zone = zone2
},

hope I’m coming across right here

Hi @21andrewmitchell,

I think something like the following would get a result like that:

variable "subnets" {
  type = list(object({
    name       = string
    cidr_block = string
  }))
}

variable "zones" {
  type = list(string)

  validation {
    condition     = length(var.zones) > 0
    error_message = "At least one zone name is required."
  }
}

locals {
  subnets_in_zones = tolist([
    for i, sn in var.subnets : {
      name       = sn.name
      cidr_block = sn.cidr_block
      zone       = element(var.zones, i)
    }
  ])
}

The above is relying on the special behavior of the element function where it responds to an index greater than the maximum list index by wrapping around to the start of the list using a modulo operation. Since i in this for expression will count up 0, 1, 2, 3, it’ll end up selecting var.zones elements 0, 1, 0, 1, which I think matches the result you were hoping for.

Because the element function requires a list with at least one element, I also added a custom validation rule to variable "zones" which should then reject an empty list at a source location in the calling module, rather than directly at the element call.

Hi @apparentlymart I have this a shot and it doesn’t seem to give the desired output, so what I am getting from thee above example where zones is a list of three zones is

subnets_in_zones = [
   {
     cidr_block = "10.0.0.0/24
     name         = "subnet1"
     zone           = "zone1"
  },
  {
     cidr_block = "10.0.1.0/24
     name         = "subnet2"
     zone           = "zone2"
  }

so rather than giving me 6 objects I am getting two

Aha, sorry I understand better now what your intent was… it sounds like you want to find every combination of subnet and zone, rather than to assign one zone to each subnet (which is what I implemented before).

Aside from the object types being different, I think what you are looking for here essentially matches the problem being described in setproduct: Finding combinations for for_each, and so hopefully the long-form explanation there will tell you about the building blocks for solving this, and then you can adapt it to your situation. If you run into problems adapting that example, please let me know what you’ve tried and I’ll try to see what’s missing. Thanks!