Post

Filtering arrays in bicep

Introduction

When working with bicep to create azure resources, there can be times where you have an array as input, but you actually want to filter this array in order to only select certain members. This can be a little difficult. For instance there are two different ways you could do this:

  1. When using a module deployment, you can use for to loop through the array and use if to determine which array members to process or not
  2. Another option is to use a variable and use the ternary operator bicep provides to loop through the array with a condition

Downside of the first option is that you may not know the length of the resulting ‘module’ array. This makes it hard to access the output from the module and might prevent you to use this in subsequent deployments

Downside of the second option is that you have to use the ternary operator and this means that you always have to use ‘something’ for the false value. Let’s look at option 2 a little closer.

Using the ternary operator to select array members:

So, lets see how it would look if we attempt to filter an array using the ternary operator in a variable.

Example bicep:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var myArray = [
  {
    name: 'name1'
    condition: 'all'
  }
  {
    name: 'name2'
    condition: 'yes'
  }
  {
    name: 'name3'
    condition: 'no'
  }
  {
    name: 'name4'
    condition: 'no'
  }
]


var abc = [for (item, i) in myArray:item.condition == 'all' || item.condition == 'yes' ? item : []]


output myArray array = abc

The problem is that this results in an array with empty members:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
    "outputs": {
        "myArray": {
            "type": "Array",
            "value": [
                {
                    "condition": "all",
                    "name": "name1"
                },
                {
                    "condition": "yes",
                    "name": "name2"
                },
                [],
                []
            ]
        }
    }
}

This is most likely not wat you want. So, is there a solution?

Solution

I have looked at this before and I have failed to find a proper solution for this. But last week a colleague of mine asked the question again, so I went back and looked at it again. I was almost ready to give up, until I realised the intersection array funtions provides the solution!

Intersection provides, well, the intersection of two arrays. In other words, it selects only those members which both arrays have in common. So for out scenario, the common members of both arrays are exactly those members we wish to select.

In other words, changing the example above:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var myArray = [
  {
    name: 'name1'
    condition: 'all'
  }
  {
    name: 'name2'
    condition: 'yes'
  }
  {
    name: 'name3'
    condition: 'no'
  }
  {
    name: 'name4'
    condition: 'no'
  }
]


var abc = [for (item, i) in myArray:item.condition == 'all' || item.condition == 'yes' ? item : []]
var abc2 = intersection(abc, myArray)


output myArray array = abc2 

This will result in the output:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
    "outputs": {
        "myArray": {
            "type": "Array",
            "value": [
                {
                    "condition": "all",
                    "name": "name1"
                },
                {
                    "condition": "yes",
                    "name": "name2"
                }
            ]
        }
    }
}

And this is exactly what we were looking for.

This post is licensed under CC BY 4.0 by the author.