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.
Related
This question already has answers here:
What is the difference between shallow copy, deepcopy and normal assignment operation?
(12 answers)
Closed 2 years ago.
I have two sets of code which demonstrate shallow copy but I am not able to explain why the code behaves differently.
The first set of code:
import copy
cv1 = [1,2,3]
cv2 = copy.copy(cv1)
print(cv1)
print(cv2)
cv2[0] = 0
cv1[1] = 1
print(cv1)
print(cv2)
The output :
[1, 2, 3]
[1, 2, 3]
[1, 1, 3]
[0, 2, 3]
Second set of code:
import copy
a = [ [1, 2, 3], [4, 5, 6] ]
b = copy.copy(a)
print(a)
print(b)
a[1][2] = 25
b[0][0] = 98
print(a)
print(b)
The output :
[[1, 2, 3], [4, 5, 6]]
[[1, 2, 3], [4, 5, 6]]
[[98, 2, 3], [4, 5, 25]]
[[98, 2, 3], [4, 5, 25]]
In my understanding, both codes should do the exact same thing. Why is that after the second set of print statements in each code snippet, the contents of cv1 and cv2 are different while a and b are the same.? Maybe it is a very basic error on my side, I am new to Python, but I can't seem to figure this out. Any help is appreciated.
This has to do with the copy library you imported.
copy.copy(x)
Return a shallow copy of x.
A shallow copy constructs a new compound object and then (to the extent possible) inserts > references into it to the objects found in the original.
So in the first case the copy is creating a new list of int object while the second case it is creating a list of references object.
While in the second case the list a and b are different, they contain the same lists inside. Thats why changing one of those list inside will edit both lists.
For the two cases to be the same you need to use the copy.deepcopy function.
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
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.
Okay, so I have this function that I need to create and I think the code checker is somehow flawed and I tried manage it but my code still seems to fail
def reversecomp(L):
""" assumes L is a list of lists whose elements are ints
Mutates L such that it reverses its elements and also
reverses the order of the int elements in every element of L.
It does not return anything.
"""
if L == []:
return L
elif type(L) == int:
return L
else:
return reversecomp(L[1:]) + [reversecomp(L[0])]
def run_code(L):
return reversecomp(L)
print(L)
The question states that you need to mutate L. Your code must work when you do this:
L = [[0, 1, 2], [1, 2, 3], [3, 2, 1], [10, -10, 100]]
reversecomp(L)
print(L)
Test: run_code([[0, 1, 2], [1, 2, 3]])
Your output:
[[3, 2, 1], [2, 1, 0]]
Correct output:
[[3, 2, 1], [2, 1, 0]]
None
The spec says "It does not return anything"; your program does.
L is a list of lists of ints
Okay, so why are you checking type(L) == int when type(L) == list is always true, per the specification?
Mutates L
You're not mutating L at all; you're returning a new list. Mutating L means doing something like L[...] = xxx.
It does not return anything.
You shouldn't be using the return keyword at all in reversecomp.
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, ]