I am struggling with seemingly simple task in Terraform. I would easily do it with Ruby/Python with local variable inside the for loop, but Terraform doesn't have those.
Here is an issue.
I have a list with multiple duplicate string occurances:
list = ["a","b","c","a","b","c","a"]
I want to count how many times the same string occured from the beginning, but keep the count in the same location, so the resulting list would become this:
index_list = [1, 1, 1, 2, 2, 2, 3]
Is it possible with Terraform?
We can do the following:
locals {
lst = ["a", "b", "c", "a", "b", "c", "a"]
index_list = [for index, item in local.lst : length([for i in slice(local.lst, 0, index + 1) : i if i == item])]
}
output "index_list" {
value = local.index_list
}
Output for index_list:
index_list = [
1,
1,
1,
2,
2,
2,
3,
]
The first for loop iterates through the list. The second for loop is a slice combined with a filter. The slice function creates a sublist from the first element to the index if the current element. With the filter (if i == item) we filter out from this sublist all the elements which are equal to the current element. Last but not least, we get the length of this filtered list.
Related
I made a list with some character in it and I looped through it to calculate the number of a specific character and it returns the number of all the characters inside the list and not the one's that I said it to. Take a look at my code and if someone can help I will appreciate it!
This is the code:
array = ['a', 'b', 'c', 'a']
sum_of_as = 0
for i in array:
if str('a') in array:
sum_of_as += 1
print(f'''The number of a's in this array are {sum_of_as}''')
If you know the list is only ever going to contain single letter strings, as per your example, or if you are searching for a word in a list of words, then you can simply use
list_of_strings = ["a", "b,", "c", "d", "a"]
list_of_strings.count("a")
Be aware though that will not count things such us
l = ["ba", "a", "c"] where the response would be 1 as opposed to 2 when searching for a.
The below examples do account for this, so it really does depend on your data and use case.
list_of_strings = ["a", "b,", "c", "d", "ba"]
count = sum(string.count("a") for string in list_of_strings)
print(count)
>>> 2
The above iterates each element of the list and totals up (sums) the amount of times the letter "a" is found, using str.count()
str.count() is a method that returns the number of how many times the string you supply is found in that string you call the method on.
This is the equivalent of doing
count = 0
list_of_strings = ["a", "b,", "c", "d", "ba"]
for string in list_of_strings:
count += string.count("b")
print(count)
name = "david"
print(name.count("d"))
>>> 2
The if str('a') in array evaluates to True in every for-loop iteration, because there is 'a' in the array.
Try to change the code to if i == "a":
array = ["a", "b", "c", "a"]
sum_of_as = 0
for i in array:
if i == "a":
sum_of_as += 1
print(sum_of_as)
Prints:
2
OR:
Use list.count:
print(array.count("a"))
I have a list:
my_list = ['coffee', 'sunshine', 'hiking', 'stocks', 'mountains', 'space', 'Travel']
I would like to count the occurrence of a specific letter across all the elements in that list, let's say the letter 's'.
Can this be achieved without loops?
Join the words, you then get a string where you can use the count() method to get the number of occurence of a letter.
"".join(my_list).count("a")
You can use the map function provided you want the count of the character in each string in the given list.
my_list = ['coffee', 'sunshine', 'hiking', 'stocks', 'mountains', 'space', 'Travel']
count_s = list(map(lambda n: n.count('s'), my_list))
print(count_s)
[0, 2, 0, 2, 1, 1, 0]
This is a program that I recently made. The goal of this code is to a pair of corresponding lists. So randomStringpt1[0] corresponds to randomStringpt2[0]. I want to compare randomStringpt1[0] and randomString2[0] to the rest of the pairs that the user gave in the randomStrings. But after using this code, it looks like I have duplicated each pair many times, which is the opposite of what I was looking for. I was thinking of using a dictionary, but then realized that a dictionary key could only have one value, which wouldn't help my case if the user used a number twice. Does anyone know how I can reduce the duplicates?
(The tests I have been running have been with the numbers randomStringpt1 = [1,3,1,1,3] and randomStringpy2 = [2,4,2,3,4]
)
randomStringpt1 = [1, 2, 3, 4, 5] #Pair of strings that correspond to each other("1,2,3,4,5" doesn't actually matter)
randomStringpt2 = [1, 2, 3, 4, 5]
for i in range(len(randomStringpt1)):
randomStringpt1[i] = input("Values for the first string: ")
randomStringpt2[i] = input("Corresponding value for the second string: ")
print(randomStringpt1) #numbers that the user chose for the first number of the pair
print(randomStringpt2) #numbers that the user chose for the second number of the pair
newStart = []
newEnd = []
for num1 in range(len(randomStringpt1)):
for num2 in range(len(randomStringpt1)):
if (int(randomStringpt1[num1]) != int(randomStringpt1[num2]) and int(randomStringpt2[num1]) != int(randomStringpt2[num2])):
newStart.append(randomStringpt1[num1]) # Adding the pairs that aren't equal to each other to a new list
newEnd.append(randomStringpt2[num1])
newStart.append(randomStringpt1[num2])
newEnd.append(randomStringpt2[num2])
# else:
# print("The set of numbers from the randomStrings of num1 are not equal to the ones in num2")
print(newStart)
print(newEnd)
First let's analyze the 2 bugs in your code,
the if condition inside the loop is true every time a pair compares to a different one. this means for your example it should output
[1, 1, 3, 3, 3, 1, 1, 1, 1, 3, 3, 3]
[2, 2, 4, 4, 4, 2, 2, 3, 3, 4, 4, 4]
since you compare every pair to any other pair that exists. But your output is different because you append both pairs every time and getting a very big result, so you shouldn't append the num2 pairs.
Now, from what you described that you want, you should loop every pair and check if it already exists in the output list. So the for loop part can change like this
filtered = []
for pair in zip(randomStringpt1,randomStringpt2):
if pair not in filtered:
filtered.append(pair) # Adding the pairs that aren't equal to each other to a new list
the zip function takes the 2 lists and for every loop it returns 2 values one from each list the first value pair, then the second values and goes on. the filtered list will be in the following format [(1, 2), (3, 4), (1, 3)]
Alternative it can be as a one liner like this:
filtered = list(dict.fromkeys(zip(randomStringpt1, randomStringpt2)))
using the dictionary to identify unique elements and then turn it back into a list
after all that you can get the original format of the lists you had in your code by splitting them like this
newStart = [pair[0] for pair in filtered]
newEnd = [pair[1] for pair in filtered]
Finally i should tell you to read a little more on python and it's for loops, since the range(len(yourlist)) is not the python intended way to loop over lists, as python for loops are equivalent to for each loops on other languages and iterate over the list for you instead on relying in a value to get list elements like yourlist[value].
This is simple in other language by using for or do while statement. Being a novice, I still can't figure out to do it in Terraform.
The real case that I need to do is to build a connection string to mongoDB replica-set service. The replication_factor is 3, 5 or 7 which means I need to create a list of 2, 4, or 6 hostnames/addresses.
I come up with the following code sofar:
locals {
uri_list = [
"#${alicloud_mongodb_instance.tyk_mongodb-test.id}1.mongodb.${var.region}.rds.aliyuncs.com:${var.db_port}",
"#${alicloud_mongodb_instance.tyk_mongodb-test.id}2.mongodb.${var.region}.rds.aliyuncs.com:${var.db_port}",
"#${alicloud_mongodb_instance.tyk_mongodb-test.id}3.mongodb.${var.region}.rds.aliyuncs.com:${var.db_port}",
"#${alicloud_mongodb_instance.tyk_mongodb-test.id}4.mongodb.${var.region}.rds.aliyuncs.com:${var.db_port}",
"#${alicloud_mongodb_instance.tyk_mongodb-test.id}5.mongodb.${var.region}.rds.aliyuncs.com:${var.db_port}",
"#${alicloud_mongodb_instance.tyk_mongodb-test.id}6.mongodb.${var.region}.rds.aliyuncs.com:${var.db_port}"
]
uri_list_out = [
for uriname in local.uri_list :
lower(uriname)
if substr(uriname,length("${alicloud_mongodb_instance.tyk_mongodb-test.id}") + 1, 1) < var.mongos_config["${var.environment}"]["replication_factor"]
]
}
What I expect from
output "uri_list_out" {
value = local.uri_list_out
}
is the first two elements of uri_list but instead I got only [1,2] for replication_factor = 3. Seems like if instruction in for also modify the output ???
I appreciate any hints to solve this problem.
Hendro
I believe what you really need is the slice(list, startindex, endindex) function:
uri_list_out = [
for uri in slice(local.uri_list, 0, var.mongos_config[var.environment]["replication_factor"] - 1) :
replace(uri, "/^#/", "") # Remove the leading '#'
]
The docs for the slice function
> slice(["a", "b", "c", "d"], 1, 3)
[
"b",
"c",
]
Is there a way to add every number with the next one from a list and then the result to be added to the next number from the same list?
For example:
[0, 2, 5, 9]
Is there a way to get:
[0, 2, 7, 16]
I've come to:
resource "null_resource" "dmns_calc_l" {
count = "${length(local.num_cntd_and_zero_l) - 1}"
triggers {
num_calc_l = "${local.num_cntd_and_zero_l[count.index] + local.num_cntd_and_zero_l[count.index + 1]}"
}
}
locals {
num_calc_and_zero_l = [
"${0}",
"${null_resource.dmns_calc_l.*.triggers.num_calc_l}",
]
}
However, as it is clearly to see it - it is good enough only for a list of 3 elements /and if the first element is "0"/ because it does NOT add up with the previous addition result.