github.com/muratcelep/terraform@v1.1.0-beta2-not-internal-4/website/docs/language/expressions/for.html.md (about)

     1  ---
     2  layout: "language"
     3  page_title: "For Expressions - Configuration Language"
     4  description: "For expressions transform complex input values into complex output values. Learn how to filter inputs and how to group results."
     5  ---
     6  
     7  # `for` Expressions
     8  
     9  A _`for` expression_ creates a complex type value by transforming
    10  another complex type value. Each element in the input value
    11  can correspond to either one or zero values in the result, and an arbitrary
    12  expression can be used to transform each input element into an output element.
    13  
    14  For example, if `var.list` were a list of strings, then the following expression
    15  would produce a tuple of strings with all-uppercase letters:
    16  
    17  ```hcl
    18  [for s in var.list : upper(s)]
    19  ```
    20  
    21  This `for` expression iterates over each element of `var.list`, and then
    22  evaluates the expression `upper(s)` with `s` set to each respective element.
    23  It then builds a new tuple value with all of the results of executing that
    24  expression in the same order.
    25  
    26  ## Input Types
    27  
    28  A `for` expression's input (given after the `in` keyword) can be a list,
    29  a set, a tuple, a map, or an object.
    30  
    31  The above example showed a `for` expression with only a single temporary
    32  symbol `s`, but a `for` expression can optionally declare a pair of temporary
    33  symbols in order to use the key or index of each item too:
    34  
    35  ```hcl
    36  [for k, v in var.map : length(k) + length(v)]
    37  ```
    38  
    39  For a map or object type, like above, the `k` symbol refers to the key or
    40  attribute name of the current element. You can also use the two-symbol form
    41  with lists and tuples, in which case the additional symbol is the index
    42  of each element starting from zero, which conventionally has the symbol name
    43  `i` or `idx` unless it's helpful to choose a more specific name:
    44  
    45  ```hcl
    46  [for i, v in var.list : "${i} is ${v}"]
    47  ```
    48  
    49  The index or key symbol is always optional. If you specify only a single
    50  symbol after the `for` keyword then that symbol will always represent the
    51  _value_ of each element of the input collection.
    52  
    53  ## Result Types
    54  
    55  The type of brackets around the `for` expression decide what type of result
    56  it produces.
    57  
    58  The above example uses `[` and `]`, which produces a tuple. If you use `{` and
    59  `}` instead, the result is an object and you must provide two result
    60  expressions that are separated by the `=>` symbol:
    61  
    62  ```hcl
    63  {for s in var.list : s => upper(s)}
    64  ```
    65  
    66  This expression produces an object whose attributes are the original elements
    67  from `var.list` and their corresponding values are the uppercase versions.
    68  For example, the resulting value might be as follows:
    69  
    70  ```hcl
    71  {
    72    foo = "FOO"
    73    bar = "BAR"
    74    baz = "BAZ"
    75  }
    76  ```
    77  
    78  A `for` expression alone can only produce either an object value or a tuple
    79  value, but Terraform's automatic type conversion rules mean that you can
    80  typically use the results in locations where lists, maps, and sets are expected.
    81  
    82  ## Filtering Elements
    83  
    84  A `for` expression can also include an optional `if` clause to filter elements
    85  from the source collection, producing a value with fewer elements than
    86  the source value:
    87  
    88  ```
    89  [for s in var.list : upper(s) if s != ""]
    90  ```
    91  
    92  One common reason for filtering collections in `for` expressions is to split
    93  a single source collection into two separate collections based on some
    94  criteria. For example, if the input `var.users` is a map of objects where the
    95  objects each have an attribute `is_admin` then you may wish to produce separate
    96  maps with admin vs non-admin objects:
    97  
    98  ```hcl
    99  variable "users" {
   100    type = map(object({
   101      is_admin = bool
   102    }))
   103  }
   104  
   105  locals {
   106    admin_users = {
   107      for name, user in var.users : name => user
   108      if user.is_admin
   109    }
   110    regular_users = {
   111      for name, user in var.users : name => user
   112      if !user.is_admin
   113    }
   114  }
   115  ```
   116  
   117  ## Element Ordering
   118  
   119  Because `for` expressions can convert from unordered types (maps, objects, sets)
   120  to ordered types (lists, tuples), Terraform must choose an implied ordering
   121  for the elements of an unordered collection.
   122  
   123  For maps and objects, Terraform sorts the elements by key or attribute name,
   124  using lexical sorting.
   125  
   126  For sets of strings, Terraform sorts the elements by their value, using
   127  lexical sorting.
   128  
   129  For sets of other types, Terraform uses an arbitrary ordering that may change
   130  in future versions of Terraform. For that reason, we recommend converting the
   131  result of such an expression to itself be a set so that it's clear elsewhere
   132  in the configuration that the result is unordered. You can use
   133  [the `toset` function](/docs/language/functions/toset.html)
   134  to concisely convert a `for` expression result to be of a set type.
   135  
   136  ```hcl
   137  toset([for e in var.set : e.example])
   138  ```
   139  
   140  ## Grouping Results
   141  
   142  If the result type is an object (using `{` and `}` delimiters) then normally
   143  the given key expression must be unique across all elements in the result,
   144  or Terraform will return an error.
   145  
   146  Sometimes the resulting keys are _not_ unique, and so to support that situation
   147  Terraform supports a special _grouping mode_ which changes the result to support
   148  multiple elements per key.
   149  
   150  To activate grouping mode, add the symbol `...` after the value expression.
   151  For example:
   152  
   153  ```hcl
   154  variable "users" {
   155    type = map(object({
   156      role = string
   157    }))
   158  }
   159  
   160  locals {
   161    users_by_role = {
   162      for name, user in var.users : user.role => name...
   163    }
   164  }
   165  ```
   166  
   167  The above represents a situation where a module expects a map describing
   168  various users who each have a single "role", where the map keys are usernames.
   169  The usernames are guaranteed unique because they are map keys in the input,
   170  but many users may all share a single role name.
   171  
   172  The `local.users_by_role` expression inverts the input map so that the keys
   173  are the role names and the values are usernames, but the expression is in
   174  grouping mode (due to the `...` after `name`) and so the result will be a
   175  map of lists of strings, such as the following:
   176  
   177  ```hcl
   178  {
   179    "admin": [
   180      "ps",
   181    ],
   182    "maintainer": [
   183      "am",
   184      "jb",
   185      "kl",
   186      "ma",
   187    ],
   188    "viewer": [
   189      "st",
   190      "zq",
   191    ],
   192  }
   193  ```
   194  
   195  Due to [the element ordering rules](#element-ordering), Terraform will sort
   196  the users lexically by username as part of evaluating the `for` expression,
   197  and so the usernames associated with each role will be lexically sorted
   198  after grouping.
   199  
   200  ## Repeated Configuration Blocks
   201  
   202  The `for` expressions mechanism is for constructing collection values from
   203  other collection values within expressions, which you can then assign to
   204  individual resource arguments that expect complex values.
   205  
   206  Some resource types also define _nested block types_, which typically represent
   207  separate objects that belong to the containing resource in some way. You can't
   208  dynamically generate nested blocks using `for` expressions, but you _can_
   209  generate nested blocks for a resource dynamically using
   210  [`dynamic` blocks](dynamic-blocks.html).