'Terraform: changing a list of variables into one list of maps

I have 3 terraform variables which are lists.

container_ports = [5000, 5001]
container_names = ["image1", "image2"]
load_balancer_arns = ["lb1", "1b2"]

How do I change the structure into a list of maps like below?

ecs_service_lb_config = [
   {
    container_port = 5000
    container_name = "image1"
    load_balancer_arn = "lb1
   },{
    container_port = 5001
    container_name = "image2"
    load_balancer_arn = "lb2
   }
]    


Solution 1:[1]

If you are empowered to change the interface of this module then I would suggest addressing the problem at its root by redefining the variable to arrive as the list of objects you need it to be:

variable "ecs_service_load_balancers" {
  type = list(object({
    container_port    = number
    container_name    = string
    load_balancer_arn = string
  }))
}

Note that this is a list of objects rather than a list of maps, because we're specifying specific attributes that are required rather than just calling for arbitrary key/value pairs chosen by the caller.

The caller of the module would then specify this using the same syntax you showed in your question:

module "example" {
  # ...

  ecs_service_load_balancers = [
    {
      container_port    = 5000
      container_name    = "image1"
      load_balancer_arn = "lb1
    },
    {
      container_port    = 5001
      container_name    = "image2"
      load_balancer_arn = "lb2"
    },
  ]
}

An advantage of this structure is that it's clearer which attribute values belong to which of the objects; the reader of the call doesn't need to carefully correlate by index to understand which is which.


If you cannot change the interface of this module but you still want these collected together into a list of objects internally within the module then you can create the same data structure programmatically based on the individual variable values.

variable "container_ports" {
  type = list(number)
}

variable "container_names" {
  type = list(string)
}

variable "load_balancer_arns" {
  type = list(string)
}

locals {
  ecs_service_load_balancers = tolist([
    for i, n in var.container_names : {
      container_port    = var.container_ports[i]
      container_name    = var.container_names[i]
      load_balancer_arn = var.load_balancer_arns[i]
    }
  ])
}

This uses a for expression over one of the variables (I chose var.container_names arbitrarily, but it doesn't actually matter) and specifies i, n as the local symbols so that i will be the list index. The body of the for expression can then use i to index into all three of the lists, relying on the fact that they should always be the same length and always have correlated items.

I needed to declare symbol n because it's always required to declare a symbol for the current element value, but I didn't use it inline because I wrote out var.container_names[i] instead to get the same value in a way that's consistent with the other two attribute definitions, in the hope of it being easier for a future reader to understand the goal of this expression.

You can then use local.ecs_service_load_balancers to get a similar list of objects as would be produced by the single list of objects variable declaration I showed above.

Solution 2:[2]

A simple approach can be:

ecs_service_lb_config = [
 {
   container_port = element(container_port, 0)
   container_name = element(container_name, 0)
   load_balancer_arn = element(load_balancer_arn, 0)
 },{
   container_port = element(container_port, 1)
   container_name = element(container_name, 1)
   load_balancer_arn = element(load_balancer_arn, 1)
 }
]  

The problem here that is not a auto scalable code, because if you need to add more elements you need to add a new block into the map. I'm looking for a better solution, but this could be a quick fix.

But if idk why are you using 3 differente variables if you can give me a better context maybe i can give you a cleanest solution.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Martin Atkins
Solution 2 mxchxdx