Sort by value size() - groovy

I need to sort by source value size() descending:
def source =
[(firstString): [3, 2, 1],
(secondString): [3, 2, 1, 4],
(thirdString): [3]]
expected:
[(secondString): [3, 2, 1, 4],
(firstString): [3, 2, 1],
(thirdString): [3]]
I've tried to sort doing this:
source.sort { -it.value.size() }
How can I achieve this?

The following is the working code for your expected result:
def source = [
"(firstString)": [3, 2, 1],
"(secondString)": [3, 2, 1, 4],
"(thirdString)": [3]
]
def sortedResult = source.sort { -it.value.size()}
println sortedResult
Working example here on groovy console : https://groovyconsole.appspot.com/script/5104124974596096

The sort that takes a Closure as an argument does not mutate the original Map. It only returns a new map, so you need to assign it (you can assign it to itself).
source = source.sort { -it.value.size() }
With Collections, there is another type of sort that takes a Boolean as well as a Closure. In this case, the Boolean indicates whether you want to mutate the original Collection or just return a new Collection.
a = [1,3,2]
a.sort (true) { it }
assert a = [1,2,3]
This doesn't apply to Map. So use the assignment syntax above.

Related

Python's zip like function in terraform

I have 3 lists. Is there any way to add elements from each list one by one in terraform? Like the following:
for a, b, c in UNKNOWN_FUNC([1, 2, 3], [4, 5, 6], [7, 8, 9]):
...
...
The output should be like this:
[1, 4, 7]
[2, 5, 8]
[3, 6, 9]
Note 1: I have tried zipmap, but it doesn't do the job.
Note 2: The lists would always be of the same length.
You could construct a helper list for that and then iterate over it. For example:
variable "l1" {
default = [1, 2, 3]
}
variable "l2" {
default = [4, 5, 6]
}
variable "l3" {
default = [7, 8, 9]
}
locals {
new_list = [ for idx in range(0, 3):
[ var.l1[idx], var.l2[idx], var.l3[idx] ]
]
}
And to use it in for_each:
resource "ddd" "ddd"{
for_each = {for idx, val in local.new_list: idx => val}
some_attribute1 = each.value[0]
some_attribute2 = each.value[1]
some_attribute3 = each.value[2]
I'm not fully sure I understand what your goal is, but it seems like it involves reorganizing the elements to group them by their indices.
Assuming that all of your lists will always be the same length, you could achieve that with a for expression, which is comparable to a list or map comprehension in Python.
locals {
lists = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
]
pivot = [
for i, v in local.lists[0] : [
local.lists[0][i],
local.lists[1][i],
local.lists[2][i],
]
]
}
This uses the length of the first list as a proxy for the length of all of the lists, and so this would fail if not all of the lists are of the same length.

parsing infinite list into one list

I have this task building a code using recursion. The task is taking a list who can have an infinite amount of lists inside it and making it one list.
This is so far what I have:
def flat_list(array):
new_array =[]
for i in range(0,len(array)):
if len(str(array[i])) > 1:
flat_list(array[i:i+1])
else:
new_array += array[i:len(str(array))-1]
return new_array
These are the tests it needs to pass:
assert flat_list([1, 2, 3]) == [1, 2, 3]
assert flat_list([1, [2, 2, 2], 4]) == [1, 2, 2, 2, 4]
assert flat_list([[[2]], [4, [5, 6, [6], 6, 6, 6], 7]]) == [2, 4, 5, 6, 6, 6, 6, 6, 7]
assert flat_list([-1, [1, [-2], 1], -1]) == [-1, 1, -2, 1, -1]
Mine returns this:
flat_list([1, [2, 2, 2], 4])
my result: [1,[2,2,2],4]
right answer: [1,2,2,2,4]
I think my problem is with creating a new local variable of the new_array at each entry, How can I return one list with no other lists inside it?
This task is without using numpy, but if you can also show me how it can be done with numpy it will really educate me. :)
Thank you for answering
Try this:
def flatten(S):
if S == []:
return S
if isinstance(S[0], list):
return flatten(S[0]) + flatten(S[1:])
return S[:1] + flatten(S[1:])
How it works:
1. The list is passed as an argument to a recursive function to flatten the list.
2. In the function, if the list is empty, the list is returned.
3. Otherwise the function is recursively called with the sublists as the parameters until the entire list is flattened.
I suggest you the following suggestion: it iterates over the list and if the encountered item is a list, then it recursively flattens it before appending it to the resulting flattened list:
def flat_list(aList):
result = []
for i in aList:
if isinstance(i, list):
result += flat_list(i)
else:
result.append(i)
return result

how to write switch statement to identity Array Object in Crystal lang

I want to transpose only 2d Array in Crystal lang, not 1d array.
So I write switch statement below.
a = [[1,2,3],[11,12,13]]
b = [1,2,3]
class Array
def meow
case self.first
when Array
puts self.transpose
else
puts "OK"
end
end
end
a.meow
b.meow
This code does not work. How can I fix it?
Here is the error message.
Error in foo.cr:16: instantiating 'Array(Int32)#meow()'
b.meow
^~~~
in foo.cr:8: instantiating 'Array(Int32)#transpose()'
puts self.transpose
^~~~~~~~~
in /usr/share/crystal/src/array.cr:1642: undefined method 'first' for Int32
return Array(Array(typeof(first.first))).new if empty?
^~~~~
First of all, it is usually not recommended to monkey patch types from the standard library.
The problem can be solved relatively easy by assigning the array as an argument to the method and restricting the type to Array(Array). Don't need to add specifics for any sub-types.
def meow(array : Array(Array))
array.transpose
end
meow [[1, 2, 3], [11, 12, 13]] # => [[1, 11], [2, 12], [3, 13]]
meow [[1, 2, 3], ["a", "b", "c"]] # => [[1, "a"], [2, "b"], [3, "c"]]
You probably won't need a method accepting 1-dimensional arrays, so meow [1, 2, 3] will result in a compiler error.
It's possible to add an overload like this, though:
def meow(array : Array)
"OK"
end
One of solutions could be this:
a = [[1, 2, 3], [11, 12, 13]]
b = [1, 2, 3]
class Array
def meow
case self
when Array(Array(Int32))
puts self.transpose
else
puts "OK"
end
end
end
a.meow
b.meow

For loop variable initialisation from a list

Groovy allows unfolding lists in assignment, as in:
(x, y) = [1, 2]
So I assumed something similar would work in a for loop, as in:
list = [[1, 2], [2, 4], [3, 6]]
for ((elm1, elm2) in list) {...}
Which turns out to be a syntax error. Is this style not possible or is there some trick to it I'm missing?
I guess it won't work with the for loop (or I definitely don't know the syntax), however a two-argument closure can be used to iterate such a List, unfold the tuples:
def list = [[1, 2], [2, 4], [3, 6]]
assert list.collect { a, b -> a + b } == [3, 6, 9, ]

Groovy List Conversion

I'm having an issue in groovy trying to figure out how to convert a single item to a list. I have an incoming variable params.contacts, which could be a single value (e.g. 14) or it could be an array of values (e.g. 14, 15). I want to always turn it into a list. Previously, I was simply saying params.contacts.toList(), but this code fails when it's a single item. It would take a value of 14 and divide it into a list of [1, 4].
Is there a simple, elegant way of handling this problem?
One easy way, put it in a list and flatten it:
def asList(orig) {
return [orig].flatten()
}
assert [1, 2, 3, 4] == asList([1, 2, 3, 4])
assert ["foo"] == asList("foo")
assert [1] == asList(1)
One problem with this is that it'll completely flatten things, so it's not a good approach as it'll flatten lists within your list:
assert [[1, 2], [3, 4]] == asList([[1, 2], [3, 4]]) // fails!
Another way would be to use the type system to your advantage:
def asList(Collection orig) {
return orig
}
def asList(orig) {
return [orig]
}
assert [1, 2, 3, 4] == asList([1, 2, 3, 4])
assert ["foo"] == asList("foo")
assert [1] == asList(1)
assert [[1, 2], [3, 4]] == asList([[1, 2], [3, 4]]) // works!
Here, we let the type system do all the heavy lifting for us. If we've already got a collection, just return it. Otherwise, turn it into a list. Tricks like this from Java are still available to us in groovy, and we shouldn't completely throw them out when they're the right thing for the problem.

Resources