# Build map using 2 list(string)

**URL:** <https://discuss.hashicorp.com/t/build-map-using-2-list-string/7370>\
**Category:** Terraform\
**Created:** [April 3, 2020, 7:54pm UTC](https://discuss.hashicorp.com/t/build-map-using-2-list-string/7370 "2020-04-03T19:54:01Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![opsrom](https://sea2.discourse-cdn.com/hashicorp/user_avatar/discuss.hashicorp.com/opsrom/32/3204_2.png) [@opsrom](https://discuss.hashicorp.com/u/opsrom)\
**Post date:** [April 3, 2020, 7:54pm UTC](https://discuss.hashicorp.com/t/build-map-using-2-list-string/7370/1 "2020-04-03T19:54:01Z")

</div>

Hi all, Hope all are well during this difficult context 😉

I don’t find a good solution to build a map using 2 list of strings, sorry, perhaps I’m bad 😉

I have :

- variable A  
list(string) with : [“subnet-1”, Subnet-2"]

- Variable B  
list(string) with : [“172.10.0.0/16”, “10.50.0.0/16”]

And I want to build a local object with :  
Subnet-1 =\> 172.10.0.0/16  
Subnet-1 =\> 10.50.0.0/16  
Subnet-2 =\> 172.10.0.0/16  
Subnet-2 =\> 10.50.0.0/16

To do a for\_each in another resource 😉

Do you have any clue ?

Thanks

---

<div class="post-metadata">

**Author:** ![opsrom](https://sea2.discourse-cdn.com/hashicorp/user_avatar/discuss.hashicorp.com/opsrom/32/3204_2.png) [@opsrom](https://discuss.hashicorp.com/u/opsrom)\
**Post date:** [April 3, 2020, 8:41pm UTC](https://discuss.hashicorp.com/t/build-map-using-2-list-string/7370/2 "2020-04-03T20:41:10Z")

</div>

If I try a setproduct function I have (for a for\_each in another resource)

The given “for\_each” argument value is unsuitable: the “for\_each” argument  
must be a map, or set of strings, and you have provided a value of type list  
of tuple.

---

<div class="post-metadata">

**Author:** ![apparentlymart](https://sea2.discourse-cdn.com/hashicorp/user_avatar/discuss.hashicorp.com/apparentlymart/32/702_2.png) [@apparentlymart](https://discuss.hashicorp.com/u/apparentlymart)\
**Post date:** [April 3, 2020, 10:25pm UTC](https://discuss.hashicorp.com/t/build-map-using-2-list-string/7370/3 "2020-04-03T22:25:56Z")

</div>

Hi @opsrom,

The example you gave of your intended result shows four map elements, but only two unique keys. A map is a data structure where each element is identified by a _unique_ string, so a map exactly like you showed isn’t possible, but maybe you meant a map of lists instead, like this?

```auto
{
  Subnet-1 = ["172.10.0.0/16", "10.50.0.0/16"]
  Subnet-2 = ["172.10.0.0/16", "10.50.0.0/16"]
}

```

If so, I think something like this would get that result:

```auto
locals {
  subnet_ranges = {
    for pair in setproduct(var.A, var.B) : pair[0] => pair[1]...
  }
}

```

The above uses a less-common feature of [`for` expressions](https://www.terraform.io/docs/configuration/expressions.html#for-expressions): the `...` after the value expression activates _grouping mode_, where each unique key maps to a _list_ of all of the values corresponding to that key.

If I misunderstood what you’re trying to do, it would be helpful if you could share a little more about the underlying problem you are trying to solve – that is, your current goal rather than your current idea for how to meet that goal – and then I might be able to offer some broader suggestions on how to get that done with different Terraform language features.

---

<div class="post-metadata">

**Author:** ![opsrom](https://sea2.discourse-cdn.com/hashicorp/user_avatar/discuss.hashicorp.com/opsrom/32/3204_2.png) [@opsrom](https://discuss.hashicorp.com/u/opsrom)\
**Post date:** [April 4, 2020, 9:49am UTC](https://discuss.hashicorp.com/t/build-map-using-2-list-string/7370/4 "2020-04-04T09:49:20Z")

</div>

> [@apparentlymart](#):
>
> subnet\_ranges = { for pair in setproduct(var.A, var.B) : pair[0] =\> pair[1]… }

I try to build an impossible map… I’m silly !

My goal is to call a aws\_cludformation\_stack with theses values (so 4 stacks):

- subnet 1 with cidr 1
- subnet 1 with cidr 2
- subnet 2 with cidr 1
- subnet 2 with cidr 2

> template\_body = \<\<STACK  
> Resources:  
> AuthRule:  
> Type: AWS::EC2::ClientVpnRoute  
> Properties:  
> ClientVpnEndpointId: ${aws\_cloudformation\_stack.vpnclient[0].id}  
> TargetVpcSubnetId: ${???}  
> DestinationCidrBlock: ${???}  
> STACK  
> }

Perhaps I need to build a map like this :

```
routes = {
    route1 = {
      subnet = "subnet1"
      cidr = "cidr1"
    }
    route2 = {
      subnet = "subnet1"
      cidr = "cidr2"
    }
    route3 = {
      subnet = "subnet2"
      cidr = "cidr1"
    }
    route4 = {
      subnet = "subnet2"
      cidr = "cidr2"
    }
  }

```

So I can do a clean for\_each and use each.value.subnet to retreive value  
But I don’t know how to build this kind of map using my 2 list(tring) variables ? ☹

Thank you

---

<div class="post-metadata">

**Author:** ![opsrom](https://sea2.discourse-cdn.com/hashicorp/user_avatar/discuss.hashicorp.com/opsrom/32/3204_2.png) [@opsrom](https://discuss.hashicorp.com/u/opsrom)\
**Post date:** [April 4, 2020, 10:56am UTC](https://discuss.hashicorp.com/t/build-map-using-2-list-string/7370/5 "2020-04-04T10:56:11Z")

</div>

I think I have find the solution… happy saturday morning 🙂

```
locals {
  subnet_ids = ["subnetID1", "subnetID2"]
  cidrs = ["xx.xx.xx.xx/16", "yy.yy.yy.yy/16"]

  results = setproduct(local.subnet_ids, local.cidrs)
  routes = [
    for item in local.results : merge({subnet = item[0]}, {cidr = item[1]})
  ]
}

resource "random_pet" "test" {
  count = length(local.routes)

  prefix = format("%s-%s", local.routes[count.index]["subnet"], local.routes[count.index]["cidr"])
  length = 5
}

```

I can’t do a **for\_each** but seems to work with **count** (not the best but it probably works)  
I have to test in my conrete project but seems good 😉

Thanks all.

---

<div class="post-metadata">

**Author:** ![apparentlymart](https://sea2.discourse-cdn.com/hashicorp/user_avatar/discuss.hashicorp.com/apparentlymart/32/702_2.png) [@apparentlymart](https://discuss.hashicorp.com/u/apparentlymart)\
**Post date:** [April 6, 2020, 6:57pm UTC](https://discuss.hashicorp.com/t/build-map-using-2-list-string/7370/6 "2020-04-06T18:57:46Z")

</div>

Hi @opsrom! I’m glad you found a working solution. Here’s an adaptation of your most recent example to use `for_each` instead, by constructing a map from your list:

```auto
resource "random_pet" "test" {
  for_each = {
    for r in local.routes : "${r.subnet}-${r.cidr}" => r
  }

  prefix = format("%s-%s", each.value.subnet, each.value.cidr)
  length = 5
}

```

The `for` expression in the `for_each` argument projects your list into a map with generated keys like `subnetID1-xx.xx.xx.xx/16`, which contain all of the values from the object and will thus be unique across all values in the `local.routes` list.

Terraform will then track these with addresses based on those keys:

- `random_pet.test["subnetID1-xx.xx.xx.xx/16"]`

---

<div class="post-metadata">

**Author:** ![opsrom](https://sea2.discourse-cdn.com/hashicorp/user_avatar/discuss.hashicorp.com/opsrom/32/3204_2.png) [@opsrom](https://discuss.hashicorp.com/u/opsrom)\
**Post date:** [April 6, 2020, 7:54pm UTC](https://discuss.hashicorp.com/t/build-map-using-2-list-string/7370/7 "2020-04-06T19:54:31Z")

</div>

I will try this thank you 😉
