How can I split a list with multiple lists within in and store them in some sort of variable so they can be tested.
For example
[[2,3], [6,1,7,2], [3,4,1]]
Upon splitting will be something like this
[2,3]
[6,1,7,2]
[3,5,1,]
Where I can use each one of them as parameters for my other functions.
Is this possible, if so how can I produce this?
Thanks in advance, new to python sorry!
for x in [[2,3], [6,1,7,2], [3,4,1]]:
your_f(*x)
This will loop through the list of lists, selecting each sublist as x, and then unpacking the contents as parameters in your_f via the * (which has a special name somewhere).
Aka on the first iteration, the code will execute your_f(2, 3)
If you just want to extract inner lists to other variables you can use this:
li = [[2,3], [6,1,7,2], [3,4,1]]
a, b, c = li
print(a, b, c)
output is [2, 3] [6, 1, 7, 2] [3, 4, 1]
If you have a function that takes three lists you can use this:
def foo(a, b, c):
print(a, b, c)
foo(*li)
output is the same.
It is called Unpacking Argument Lists.
Related
I have two lists combined sequentially to create a nested list with python's map and zip funcionality; however, I wish to recreate this with itertools.
Furthermore, I am trying to understand why itertools.chain is returning a flattened list when I insert two lists, but when I add a nested list it simply returns the nested list.
Any help on these two issues would be greatly appreciated.
from itertools import chain
a = [0,1,2,3]
b = [4,5,6,7]
#how can I produce this with itertools?
c = list(map(list, zip(a,b)))
print(c) #[[0, 4], [1, 5], [2, 6], [3, 7]]
d = list(chain(c))
print(d) #[[0, 4], [1, 5], [2, 6], [3, 7]]
d = list(chain(a,b))
print(d) #[0, 1, 2, 3, 4, 5, 6, 7]
I'll try to answer your questions as best I can.
First off, itertools.chain doesn't work the way you think it does. chain takes x number of iterables and iterates over them in sequence. When you call chain, it essentially (internally) packs the objects into a list:
chain("ABC", "DEF") # Internally creates ["ABC", "DEF"]
Inside the method, it accesses each of these items one at a time, and iterates through them:
for iter_item in arguments:
for item in iter_item:
yield item
So when you call chain([[a,b],[c,d,e],[f,g]]), it creates a list with one iterable object: the list you passed as an argument. So now it looks like this:
[ #outer
[ #inner
[a,b],
[c,d,e],
[f,g]
]
]
chain as such iterates over the inner list, and returns three elements: [a,b], [c,d,e], and [f,g] in order. Then they get repacked by list, giving you what you had in the first place.
Incidentally, there is a way to do what you want to: chain.from_iterable. This is an alternate constructor for chain which accepts a single iterable, such as your list, and pulls the elements out to iterate over. So instead of this:
# chain(l)
[ #outer
[ #inner
[a,b],
[c,d,e],
[f,g]
]
]
You get this:
# chain.from_iterable(l)
[
[a,b],
[c,d,e],
[f,g]
]
This will iterate through the three sub-lists, and return them in one sequence, so list(chain.from_iterable(l)) will return [a,b,c,d,e,f,g].
As for your second question: While I don't know why itertools is a necessity to this process, you can do this in Python 2.x:
list(itertools.izip(x,y))
However, in 3.x, the izip function has been removed. There is still zip_longest, which will match up as many pairs as it can, and accept a filler value for extra pairs: list(zip_longest([a,b,c],[d,e,f,g,h],fillvalue="N")) returns [(a,d),(b,e),(c,f),(N,g),(N,h)] since the second list is longer than the first. Normal zip will take the shortest iterable and cut off the rest.
In other words, unless you want zip_longest instead of zip, itertools does not have a built-in method for zipping.
You can also run itertools.chain(*your_list_of_lists). For example:
for p in itertools.chain(*[[1,2],[3,4]]):
print(p)
1
2
3
4
I create a list as:
>>> seq = [1, 2, 3, 4]
Now i assign the variables as follows:
>>> a, b, c, d, *e = seq
>>> print(a, b, c, d, e)
I get output as:
>>> 1 2 3 4 []
Now i change the sequence in which i assign variables as:
>>> a, b, *e, c, d = seq
>>> print(a, b, c, d, e)
I get output as:
>>> 1, 2, 3, 4, []
So my question is Why *e variable above is always assigned an empty list regardless of where it appears?
It was a design choice, according to PEP 3132 (with my bold):
A tuple (or list) on the left side of a simple assignment (unpacking is not defined for augmented assignment) may contain at most one expression prepended with a single asterisk (which is henceforth called a "starred" expression, while the other expressions in the list are called "mandatory"). This designates a subexpression that will be assigned a list of all items from the iterable being unpacked that are not assigned to any of the mandatory expressions, or an empty list if there are no such items.
Indeed, the first example in the PEP illustrates your point:
>>> a, *b, c = range(5)
>>> a
0
>>> c
4
>>> b
[1, 2, 3]
In the first case
a, b, c, d, *e = seq
since the sequence has only four elements, a, b, c and d get all of them and the rest of them will be stored in e. As nothing is left in the sequence, e is an empty list.
In the second case,
a, b, *e, c, d = seq
First two elements will be assigned to a and b respectively. But then we have two elements after the *e. So, the last two elements will be assigned to them. Now, there is nothing left in the seq. That is why it again gets an empty list.
a, b, *e, c, d = [1, 2, 3, 4]
*e says "what's left put into e". Because you have 4 elements, empty sequence is put into e.
I have a spectra of wavelengths as a list and some number of other lists I use in a formula (using tmm.tmm_core). Is there something more efficient than iterating through the wavelength if I'm just basically doing the same thing for all wavelengths?
Example
def go(n, thk, theta):
#do stuff
return(something)
wv = [1, 2, 3, 4]
a_vec = [3, 7, 3, 9]
b_vec = [6, 5, 9, 3]
c_vec = [0, 1, 8, 9]
theta = 0
th = [10, 1, 10]
final = []
for i in range(len(wv)):
n = [a[i], b[i], c[i]]
answer = go(n, th, theta)
final.append(answer)
in reality there are maybe 5000-10000 rows. It just seems to lag a bit when I press go and I assume it's because of the iteration. Pretty new to optimizing so I haven't used any benchmarking tools or anything.
I think you're looking for the map function in Python!
>>> list1 = [1,2,3,4]
>>> list2 = [5,6,7,8]
>>> map(lambda x,y: x+y, list1, list2)
[6, 8, 10, 12]
it takes in a function (in the above case, an anonymous lambda function), one or more lists and returns another list. At each iteration within the function, both lists are iterated and the result is added to the new list. You don't need to limit yourself to the expressive power of a lambda statement; you can also use globally defined functions as in the case below:
>>> def go(a,b,c):
... return a+b+c
...
>>> map(go, list1,list2, range(9,13))
[15, 18, 21, 24]
You can put all of your lists within a custom list like C_list and use map to create a new list all_len contain the length of all lists then use a list comprehension to create the list final :
all_len=map(len,C_list)
final =[[go([a[i], b[i], c[i]], th, theta) for i in range(li)] for li in all_len]
Also if the length of a and b and c are equal you can use zip function to zip then and refuse of multiple indexing :
all_len=map(len,C_list)
z=zip(a,b,c)
final =[[go(z[i], th, theta) for i in range(li)] for li in all_len]
If you have to perform an operation on every item in the list, then you're gonna have to go through every item in the list. However, you could gain speed through the use of list comprehensions: List Comprehensions
I have seen many posts regarding how to flatten a list in Python. But I was never able to understand how this is working: reduce(lambda x,y:x+y,*myList)
Could someone please explain, how this is working:
>>> myList = [[[1,2,3],[4,5],[6,7,8,9]]]
>>> reduce(lambda x,y:x+y,*myList)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>>
Linked already posted :
How to print list of list into one single list in python without using any for or while loop?
Flattening a shallow list in Python
Flatten (an irregular) list of lists
If anybody thinks this is duplicate to other post, I'll remove it once I understood how it works.
Thanks.
What reduce does, in plain English, is that it takes two things:
A function f that:
Accepts exactly 2 arguments
Returns a value computed using those two values
An iterable iter (e.g. a list or str)
reduce computes the result of f(iter[0],iter[1]) (the first two items of the iterable), and keeps track of this value that was just computed (call it temp). reduce then computes f(temp,iter[2]) and now keeps track of this new value. This process continues until every item in iter has been passed into f, and returns the final value computed.
The use of * in passing *myList into the reduce function is that it takes an iterable and turns it into multiple arguments. These two lines do the same thing:
myFunc(10,12)
myFunc(*[10,12])
In the case of myList, you're using a list that contains only exactly one list in it. For that reason, putting the * in front replaces myList with myList[0].
Regarding compatibility, note that the reduce function works totally fine in Python 2, but in Python 3 you'll have to do this:
import functools
functools.reduce(some_iterable)
It is equivalent to :
def my_reduce(func, seq, default=None):
it = iter(seq)
# assign either the first item from the iterable to x or the default value
# passed to my_reduce
x = next(it) if default is None else default
#For each item in iterable, update x by appying the function on x and y
for y in it:
x = func(x, y)
return x
...
>>> my_reduce(lambda a, b: a+b, *myList, default=[])
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> my_reduce(lambda a, b: a+b, *myList)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> from operator import add
>>> my_reduce(add, *myList)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> my_reduce(lambda a, b: a+b, ['a', 'b', 'c', 'd'])
'abcd'
Docstring of reduce has a very good explanation:
reduce(...)
reduce(function, sequence[, initial]) -> value
Apply a function of two arguments cumulatively to the items of a sequence,
from left to right, so as to reduce the sequence to a single value.
For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates
((((1+2)+3)+4)+5). If initial is present, it is placed before the items
of the sequence in the calculation, and serves as a default when the
sequence is empty.
First of all, this is a very bad method. Just so you know.
reduce(f, [a, b, c, d]) runs
f(f(f(f(a, b), c), d)
Since f is lambda x,y:x+y, this is equivalent to
((a + b) + c) + d
For lists, a + b is the concatenation of the lists, so this joins each list.
This is slow because each step has to make a new list from scratch.
First, I don't know why it's wrapped in an array and then splatted (*). This will work the same way:
>>> myList = [[1,2,3],[4,5],[6,7,8,9]]
>>> reduce(lambda x,y:x+y,myList)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
Explanation: reduce takes a method with two parameters - the accumulator and the element. It calls the method with each element and then sets the accumulator to the result of the lambda. Therefore, you're basically concatenating all the inner lists together.
Here's a step-by-step explanation:
accumulator is initialized to myList[0] which is [1,2,3]
lambda is called with [1,2,3] and [4,5], it returns [1,2,3,4,5], which is assigned to the accumulator
lambda is called with [1,2,3,4,5] and [6,7,8,9], it returns [1,2,3,4,5,6,7,8,9]
no more elements left, so reduce returns that
I have few lists like:
a = [1, 2, 3, 4, 5]
b = [4, 6, 5, 9, 2]
c = [4, 7, 9, 1, 2]
I want to trim all of them using a loop, instead of doing as below:
a[-2:]
b[-2:]
c[-2:]
I tried but got confused with pass by value or pass by reference fundamentals, looked into other questions as well but no help.
Thanks
for l in [a, b, c]:
del l[-2:]
This removes the last two elements from each list. If you want to remove all but the last two elements only, do this:
for l in [a, b, c]:
del l[:-2]
There's no need to worry about references here; the list over which the for loop iterates contains references to a, b and c, and each list is mutated in-place by deleting a list slice.
x = [a, b, c]
x = map(lambda lst: lst[-2:], x)
Deleting the unwanted items from the existing lists, using a loop:
for list in [a, b, c]:
del a[:-2]
Or, creating new lists containing only the correct items, using a list comprehension:
(a, b, c) = [x[-2:] for x in (a, b, c)]