メインコンテンツにスキップ

flatten 関数

flatten はリストを受け取り、リストである要素をリストの内容の平坦化されたシーケンスに置き換えます。

コードブロック
> flatten([["a", "b"], [], ["c"]])
["a", "b", "c"]

ネストされたリストの中に直接ネストされたリストがある場合、それらも再帰的に平坦化されます。

コードブロック
> flatten([[["a", "b"], []], ["c"]])
["a", "b", "c"]

マップなどにある間接的にネストされたリストは、平坦化されません

for_each のためのネストされた構造の平坦化

リソース for_eachdynamic ブロックの言語機能は、どちらも各繰り返しに対して1つの要素を持つコレクション値を必要とします。

入力データ構造が、for_each 引数で使用するのに適した形状になっていない場合があります。そのような場合、flatten はネストされたデータ構造をフラットなデータ構造に変換する際に役立つ便利な関数になります。

たとえば、次のような変数を宣言するモジュールについて考えてみましょう。

コードブロック
variable "networks" {
type = map(object({
cidr_block = string
subnets = map(object({ cidr_block = string }))
}))
}

上記は、トップレベルのネットワークとそれらのサブネットなど、自然にツリーを形成するオブジェクトをモデル化するのに適した方法です。トップレベルのネットワークの繰り返しでは、結果のインスタンスがマップ要素と1対1で対応する形式になっているため、この変数を直接使用できます。

コードブロック
resource "aws_vpc" "example" {
for_each = var.networks

cidr_block = each.value.cidr_block
}

ただし、単一の resource ブロックで *サブネット* をすべて宣言するためには、最初に構造をフラット化して、各トップレベルの要素が単一のサブネットを表すコレクションを生成する必要があります。

コードブロック
locals {
# flatten ensures that this local value is a flat list of objects, rather
# than a list of lists of objects.
network_subnets = flatten([
for network_key, network in var.networks : [
for subnet_key, subnet in network.subnets : {
network_key = network_key
subnet_key = subnet_key
network_id = aws_vpc.example[network_key].id
cidr_block = subnet.cidr_block
}
]
])
}

resource "aws_subnet" "example" {
# local.network_subnets is a list, so we must now project it into a map
# where each key is unique. We'll combine the network and subnet keys to
# produce a single unique key per instance.
for_each = {
for subnet in local.network_subnets : "${subnet.network_key}.${subnet.subnet_key}" => subnet
}

vpc_id = each.value.network_id
availability_zone = each.value.subnet_key
cidr_block = each.value.cidr_block
}

上記の結果、サブネットオブジェクトごとに1つのサブネットインスタンスが生成され、サブネットとそれらを含むネットワークとの関連性が保持されます。

  • setproduct は、複数のリストまたは値のセットのすべての組み合わせを見つけます。これは for_each 構造で使用するコレクションを準備する際に役立ちます。