how to append a list of lists in Groovy - groovy

How do I append a list of lists in a purely functional way in groovy? Like if I have a list in variable "a", with a method "b" that returns a list, I can do this:
a.*b
=> [[1, 2], [3, 4, 5], [6]]
but what I really want is:
[1, 2, 3, 4, 5, 6]
This would be easy for example in the Scheme programming language:
(define foo '((1 2) (3 4 5) (6)))
(apply append foo)
=> (1 2 3 4 5 6)
how to do (apply append list-of-lists) in groovy? I know I can do flatten() but that goes arbitrarily deep, and that's not what I want.

Your example code shows the spread-operator. So instead of using that,
you can use collectMany.
If you prefer to build the intermediate result and then "apply" one
function to merge all lists, you can use sum, which on an array
concats all elements.
def a = [[b:[1]],[b:[2,[3]]]]
println(a.collectMany{ it.b })
// → [1, 2, [3]]
println(a*.b.sum())
// → [1, 2, [3]]

Related

How can I get multiple output variables into a list?

I'm wondering if there's a way of getting multiple outputs from a function into a list. I'm not interested in creating a list inside of a function for reasons I'm not going to waste your time going into.
I know how many output variables I am expecting, but only through using the annotations["return"] expression (or whatever you call that, sorry for the noobish terminology) and this changes from case to case, which is why I need this to be dynamic.
I know I can use lists as multiple variables using function(*myList), but I'm interested in if there's a way of doing the equivalent when receiving return values from a function.
Cheers!
Pseudocode:
function():
x = 1
y = 2
return x, y
variables = function()
print(variables[0], " and ", variables[1]
result should be = "1 and 2"
yes, with the unpacking assignments expression ex a,b,c= myfunction(...), you can put * in one of those to make it take a variable number of arguments
>>> a,b,c=range(3) #if you know that the thing contains exactly 3 elements you can do this
>>> a,b,c
(0, 1, 2)
>>> a,b,*c=range(10) #for when you know that there at least 2 or more the first 2 will be in a and b, and whatever else in c which will be a list
>>> a,b,c
(0, 1, [2, 3, 4, 5, 6, 7, 8, 9])
>>> a,*b,c=range(10)
>>> a,b,c
(0, [1, 2, 3, 4, 5, 6, 7, 8], 9)
>>> *a,b,c=range(10)
>>> a,b,c
([0, 1, 2, 3, 4, 5, 6, 7], 8, 9)
>>>
additionally you can return from a function whatever you want, a list, a tuple, a dict, etc, but only one thing
>>> def fun():
return 1,"boo",[1,2,3],{1:10,3:23}
>>> fun()
(1, 'boo', [1, 2, 3], {1: 10, 3: 23})
>>>
in this example it return a tuple with all that stuff because , is the tuple constructor, so it make a tuple first (your one thing) and return it

How do I flatten a list containing both values and other lists? [duplicate]

This question already has answers here:
Flatten an irregular (arbitrarily nested) list of lists
(51 answers)
Closed 1 year ago.
For instance, I could have this list:
l = [1, [2, 3], [4, 5, [6, 7], 8]]
and I want to flatten the list like this:
l = [1, 2, 3, 4, 5, 6, 7, 8]
I found some methods online for doing this, but they assume that the list doesn't contain any values outside of sub-lists, or have side effects like reversing the order of elements. What's the best way to do this?
[Edit] I got an existing question recommended, but I couldn't understand what "yield from" does in Python, as I haven't seen it before in that context.
# initializing the data and empty list
data = [1, [2, 3, [4, 5]], 6, [[7], [8, 9]]]
flat_list = []
# function
def flatten_list(data):
# iterating over the data
for element in data:
# checking for list
if type(element) == list:
# calling the same function with current element as new argument
flatten_list(element)
else:
flat_list.append(element)
# flattening the given list
flatten_list(data)
# printing the flat_list
print(flat_list)
(See more at https://geekflare.com/flatten-list-python/)

Understanding the shallow copy in Python [duplicate]

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.

How to transform a list of lists like [1, [2, 3, 4], 5 ] to a list [[1,2,5], [1,3,5], [1,4,5]] in Python?

I'm just starting with Python and trying to find a general solution to transform a list of lists [1, [2, 3, 4], 5 ] to a list [[1,2,5], [1,3,5], [1,4,5]] in Python.
I've tried creating some dynamic lists but not getting what i want, not even for this simple list in the example. Any help will be greatly appreciated.
inter_l = []
aba = []
v = [1, [2, 3], 4, 5, 6]
g = globals()
for elem in v:
if isinstance(elem, (list,)):
l_ln = len(elem)
indx = v.index(elem)
for i in range(0, l_ln):
g['depth_{0}'.format(i)] = [elem[i]]
inter_l.append(list(g['depth_{0}'.format(i)]))
else:
aba.append(elem)
t = aba.extend(inter_l)
w = aba.extend(inter_l)
print(v)
print(aba)
print(inter_l)
[1, [2, 3], 4, 5, 6]
[1, 4, 5, 6, [2], [3], [2], [3]]
[[2], [3]]
The easiest way would be to leverage itertools.product function, but since it expects iterables as its inputs, the input would have to be transformed a little. One way to achieve this would be something like this:
transformed = [e if isinstance(e, list) else [e] for e in v]
which converts all non-list elements into lists and then pass this transformed input to product:
list(itertools.product(*transformed))
Note, that * in front of transformed expands transformed list into positional arguments, so that instead of a single argument of type list, a list of its elements is passed instead.
The entire pipeline looks something like this:
>>> v = [1, [2, 3, 4], 5]
>>> t = [e if isinstance(e, list) else [e] for e in v]
>>> list(itertools.product(*t))
[(1, 2, 5), (1, 3, 5), (1, 4, 5)]

how does xs in this function work?

I am reading Hutton's book, Programming in Haskell.
Here is a function:
pairs :: [a] -> [(a,a)]
pairs xs = zip xs (tail xs)
e.g.
>pairs [1,2,3,4]
>[(1,2),(2,3),(3,4)] --result
Problem is how to read this function ? from left to right?
I am confused how "tail" leave 1 element and then combine it with next element using "zip"
Since "tail" suppose to get all remaining elements from the list right?
I haven't read the book you mentioned, but I'll try to explain what I know.
You're right about the tail function returning everything except the first element of the list. Let's see how zip works,
zip [1, 2, 3, 4] [5, 6, 7, 8]
gives,
[(1, 5), (2, 6), (3, 7), (4, 8)]
Now, consider the output we need from the input we have, observe the transformation required from input to output,
[1, 2, 3, 4] -> [(1,2),(2,3),(3,4)]
From the above application of zip, we can see the output we need can be obtained by calling zip with,
zip [1, 2, 3] [2, 3, 4]
Now, from the docs on zip function, we can see that if the two given lists are of unequal length, the extra items in the longer list are discarded. So, we'd get the same result with,
zip [1, 2, 3, 4] [2, 3, 4]
in which the last 4 in the first input list would be discarded and we get the result we want.
This can be written in a function as,
pairs xs = zip xs (tail xs)
If it is something else you are confused about, do let me know.
zip takes 2 arguments. tail returns its argument with the first element removed, but does not modify its argument.Therefore [1, 2, 3, 4] gets zipped with [2, 3, 4].

Resources