-
Notifications
You must be signed in to change notification settings - Fork 615
Description
Description
I would like the ability to convert a list from rows into columns, AFAIK the typical term for this functionality is transpose.
It can currently be implemented via a user-defined function but may be worthwhile functionality for Docker Bake to include in it's stdlib functions:
function transposelist {
params = [nested_list]
result = [
for i in range(0, length(nested_list[0])):
nested_list[*][i]
]
}FWIW, Terraform has similar functionality for maps of lists as a transpose collection function.
Reference
For context, I'm aware of some related functionality in HCL and Docker Bake.
Related functionality:
- This functionality is similar to the
matrixfield intargetblocks, but could be leveraged elsewhere such as via user-defined functions or global scope attributes. - HCL also has the splat syntax such that you can get a new list by a sublist index across all elements, or from a common key of each object element:
# Splat with indices: example = [["a", "1"], ["a", "2"], ["a", "3"]] formatlist("Left: %s, Right: %s", example[*][0], example[*][1]) # This is equivalent to `example...`, it does not spread a splat of all indices: formatlist("Left: %s, Right: %s", example[*]...) map_example = [{a: "1"}, {"a": "2"}, {"a": "3"}] formatlist("Value of key `a`: %s", map_example[*].a)
AFAIK the splat syntax lacks a way to do full transposition of the list, so you would need to repeat it for each element unless it could take a range.
There is also the ... spread operator that can only be used as the last parameter to a function, expanding a list of values into additional args.
Without a key or index applied after a splat, the list will remain unchanged, making the use of ... unhelpful towards transposition as example[*]... / example[*][...] / example[*...] are not valid forms to express transpose all element indices of a list.
Instead you either splat each index explicitly (as shown above), or via a for expression:
# Produces: [["a", "1"], ["a", "2"], ["a", "3"], ["b", "1"], ["b", "2"], ["b", "3"]]
matrix = setproduct(["a", "b"], ["1", "2", "3"])
# Currently to transpose a list you would need to know the fixed range
# to iterate and splat each column into a new collection:
# Transpose to: [["a", "a", "a", "b", "b", "b"], ["1", "2", "3", "1", "2", "3"]]
transposed = [for i,v in matrix[0]: matrix[*][i]]
# Proposed:
# This enables a list produce like `setproduct()` as the input without
# reliance on a reference like the the `for` expression needs.
transposed = transposelist(
setproduct(["a", "b"], ["1", "2", "3"])
)This approach is compatible with ... to expand list elements into args:
# Current workaround (assuming a reference is available for the input):
formatlist("Left: %s, Right: %s", [for i,v in matrix[0]: matrix[*][i]]...)
# Proposed is capable of inlining the value instead of depending upon a reference:
formatlist("Left: %s, Right: %s", transposelist(matrix)...)