# Terraform HCL Intro 7: For In Loop Basics

In this post, we’ll cover the Terraform `for in`

loop construct. Though it performs looping, its primary purpose is really for manipulating data structures. You can do a few things to data structures with it:

**Transform**: Change the data structure.**Filter**: Select only desired items.**Group**: Group elements together in a new List by a key.

## Input Source and Output Result

The input source and output result can be either be a List or a Map. Then `for`

will either transform and or filter it. Here’s a diagram to help explain:

## Simple Transformations Examples

Though the `for`

syntax is pretty straightforward in these examples, it can get confusing without understanding how different types work with it.

**List to List**

Here’s an example with a List input source:

```
locals {
list = ["a","b","c"]
}
output "list" {
value = [for s in local.list : upper(s)]
}
```

Returns in:

```
$ terraform apply
Outputs:
list = ["A", "B", "C"]
```

A straightforward upper transformation has been done. The resulting value is another List. This is indicated by the surrounding `[...]`

square brackets. Yes, the surrounding brackets indicate what value type is returned. So it’s important to pay attention to what they are.

**Map to List**

Here’s another example with a Map as the input source:

```
locals {
list = {a = 1, b = 2, c = 3}
}
output "result1" {
value = [for k,v in local.list : "${k}-${v}" ]
}
output "result2" {
value = [for k in local.list : k ]
}
```

Results in:

```
$ terraform apply
Outputs:
result1 = ["a-1", "b-2", "c-3"]
result2 = [1, 2, 3]
```

So when the input source is a Map, you can access the key and value. The resulting value is another List. This is indicated by the surrounding `[...]`

square brackets again.

**List to Map**

The examples we’ve been using have a resulting Output type of List due to the `[...]`

square brackets. To return a Map type instead, we would use the `{...}`

curly brackets. Here’s an example:

```
locals {
list = ["a","b","c"]
}
output "result" {
value = {for i in local.list : i => i }
}
```

Results in:

```
$ terraform apply
Outputs:
result = {
"a" = "a"
"b" = "b"
"c" = "c"
}
```

As you can see, the result output type is a Map now. It is important to note that we must provide an expression with the `=>`

when returning a Map. Otherwise, you’ll get this error:

```
Error: Invalid 'for' expression
on main.tf line 5, in output "result":
5: value = {for i in local.list : i }
```

**Map to Map**

Now a Map to Map example:

```
locals {
list = {a = 1, b = 2, c = 3}
}
output "result" {
value = {for k,v in local.list : k => v }
}
```

Results in:

```
$ terraform apply
Outputs:
result = {
"a" = 1
"b" = 2
"c" = 3
}
```

## Review & Reiterate

The wrapping bracket indicates return value type:

- When a for expression is wrapped in square brackets
`[...]`

, the result type is a List. - When a for expression is wrapped in curly brackets
`{...}`

, the result type is a Map. - Also, when returning a Map, the expression elements are separated by
`=>`

.

We’ve only shown simple transformations to introduce things. You can do many more transformations with Terraform functions.

## Multi-Line Expression

When the transformation logic gets more complicated, it can be nice to write `for`

expressions across multiple lines.

```
locals {
list = ["a","b","c"]
}
output "list" {
value = [
for s in local.list :
upper(s)
]
}
locals {
map = {a = 1, b = 2, c = 3}
}
output "map" {
value = {
for k,v in local.map :
k => v
}
}
```

Results in:

```
$ terraform apply
Outputs:
list = ["A", "B", "C"]
map = { "a" = 1, "b" = 2, "c" = 3 }
```

## Simple Filtering Examples

We can also filter the Input to an Output result. This means filtering always results in a collection that is smaller or equal to the original Input size. Filtering is achieved by tacting on the `if`

clause to the end of the transformation expression. Let’s go through some examples:

**Filter Simple Number Elements**

In this example, we’ll filter for numbers that are less than 3.

```
locals {
list = [1,2,3,4,5]
}
output "list" {
value = [for i in local.list : i if i < 3]
}
```

Results in:

```
$ terraform apply
Outputs:
list = [1, 2]
```

**Filter Map Elements**

In this example, the elements are Maps. We’ll transform the data to only return the values, but only if the b key’s value is greater than 6.

```
locals {
list = [
{a = 1, b = 5},
{a = 2, b = 6},
{a = 3, b = 7},
{a = 4, b = 8},
]
}
output "list" {
value = [for m in local.list : values(m) if m.b > 6 ]
}
```

Results in:

```
$ terraform apply
Outputs:
list = [
[3,7]
[4,8],
]
```

**Filter Inconsistent Map Elements**

Let’s say the Map elements are a little bit inconsistent, like some of them lack the b key. We can filter for that.

```
locals {
list = [
{a = 1, b = 5},
{a = 2},
{a = 3},
{a = 4, b = 8},
]
}
output "list" {
value = [for m in local.list : m if contains(keys(m), "b") ]
}
```

Results in:

```
$ terraform apply
Outputs:
list = [
{"a" = 1, "b" = 5},
{"a" = 4, "b" = 8},
]
```

## Splats

Let’s cover splats also. Splats are a shorthand way to write `for in`

expressions. These 2 expressions produce the same result:

**for in expression**

```
[for minion in local.minions : minion.name ]
```

**splat expression**

```
local.minions[*].name
```

Here’s a working example:

```
locals {
minions = [{
name: "bob"
},{
name: "kevin",
},{
name: "stuart"
}]
}
output "minions" {
value = local.minions[*].name
}
```

Results in:

```
$ terraform apply
Outputs:
minions = [
"bob",
"kevin",
"stuart",
]
```

## Group Mode

The final form of `for`

we’ll cover is group mode. The syntax is a little weird for this one. You use it by adding `...`

to the end of the value expression. Example:

```
locals {
list = [
"mr bob",
"mr kevin",
"mr stuart",
"ms anna",
"ms april",
"ms mia",
]
}
output "list" {
value = {for s in local.list : substr(s, 0, 2) => s...}
}
```

Results in:

```
$ terraform apply
Outputs:
list = {
"mr" = [
"mr bob",
"mr kevin",
"mr stuart",
]
"ms" = [
"ms anna",
"ms april",
"ms mia",
]
}
```

Group mode works kind of like SQL `group by`

. The key is used as the `group by`

and groups items together in a List.

## Summary

In this post, we covered the basics of the `for in`

loop construct. It is useful for data manipulation. In the next post, we’ll cover more practical examples of the `for`

construct.

**Want It to be Easier to Work with Terraform?**

Check out Terraspace: The Terraform Framework.