I am asking this question related to this one:
Access multiple elements of list knowing their index
Basically if you have a list and want to get several elements you cannot just pass a list of indexes.
Example:
a = [-2,1,5,3,8,5,6]
b = [1,2,5] # list of indexes
a[b] #this doesn't work
# expected output: [1,5,5]
To solve this problem several options are proposed in the linked question:
Using list comprehension:
a = [-2,1,5,3,8,5,6]
b = [1,2,5]
c = [a[i] for i in b]
Using operator.itemgetter:
from operator import itemgetter
a = [-2, 1, 5, 3, 8, 5, 6]
b = [1, 2, 5]
print itemgetter(*b)(a)
or using numpy arrays (which DO accept indexing with lists)
import numpy as np
a = np.array([-2, 1, 5, 3, 8, 5, 6])
b = [1, 2, 5]
print list(a[b])
My question is: Why normal lists don't accept this? This will not conflict the normal indexing [start:end:step] and will provide another way of accessing list elements without using external libraries.
I don't intend this question to attract opinion based answers but rather to know if there is an specific reason why this feature is not available in Python, or if it will be implemented in a future.
Another way we can get the expected output, and it might can be implemented into python function related with list.
a = [-2,1,5,3,8,5,6]
b = [1,2,5]
def getvalues(original_list, indexes_list):
new_list = []
for i in indexes_list:
new_list.append(original_list[i])
return new_list
result = getvalues(a, b)
print(result)
A simple and easy approach to do it can be done in a list comprehension:
a = [-2,1,5,3,8,5,6]
b = [1,2,5]
multi_index = lambda l1, l2: [l1[i] for i in l2]
>>> print(multi_index(a,b))
[1, 5, 5]
Related
Let's say I have:
a=[1,2,3]
b=[4,5,6]
Now I want to create a list of list from a and b, I would do it like this:
c=[a,b]=[[1,2,3],[4,5,6]]
As a.append(b) would result in: [1,2,3,b]=[1,2,3,[4,5,6]]
Now let's say there exists anew list which I want to append to c:
d=[7,8,9]
I now have to do c.append(d) to get [[1,2,3],[4,5,6],[7,8,9]]
Because
e=[c,d]=[[[1,2,3],[4,5,6]],[7,8,9]]
How can I get a list of list from individual lists without know how my lists are structured?
Try this:
a = [1,2,3]
b = [4,5,6]
c = []
c.append(a)
c.append(b)
This should work, and only takes 2 simple lines.
The two actions you are describing are distinctly different. The first is creating the outer list (a.k.a. c) and the second is appending to it.
To make the process more uniform you can just start off with an outer list and append all the child lists to it.
c = []
a=[1,2,3]
b=[4,5,6]
d=[7,8,9]
c.append(a)
c.append(b)
c.append(d)
c is now
[[[1,2,3],[4,5,6]],[7,8,9]]
A bit roundabout of a way but looks nice, using numpy
a = np.array([[1,2,3]])
b = np.array([[4,5,6]])
c = np.append(a,b,axis=0)
print(c.tolist())
gives you
[[1,2,3],[4,5,6]]
Appending another list in the same way keeps the structure of list of lists, for example
d = np.array([[7,8,9]])
e = np.append(c,d,axis=0)
print(e.tolist())
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
Now this is quite roundabout. I would just keep everything in numpy arrays if possible.
EDIT: Figured out how to do this without numpy
Simply state each list as a list of lists to begin with
a = [[1,2,3]]
b = [[4,5,6]]
a.extend(b)
print(a)
[[1,2,3],[4,5,6]]
Furthermore you can do this
d = [[7,8,9]]
a.extend(d)
print(a)
[[1, 2, 3], [4, 5, 6], [4, 5, 6]]
How do I add elements of lists within a list component wise?
p=[[1,2,3],[1,0,-1]]
I have tried the following:
list(map(sum,zip(p[0],p[1])))
Will get me [2,2,2] which is what I need. But how to extend it for a variable number of lists? For example, p=[[1,2,3],[1,0,-1],[1,1,1]] should yield [3,3,3].
A solution I figured out is the following:
import pandas as pd
p=[[1,2,3],[1,0,-1],[1,1,1]]
list(pd.DataFrame(p).sum())
Is there a more "Pythonic" way to solve this problem?
Use * for unpack lists:
a = list(map(sum,zip(*p)))
print (a)
[3, 3, 3]
In numpy solution is similar like in pandas:
a = np.array(p).sum(axis=0).tolist()
print(a)
[3, 3, 3]
You can use * to unpack the list and sum to sum it up.
If you are uncomfortable with the map function you can do it like this:
p = [[1, 2, 3], [4, 5, 6], [-5,-7,-9]]
sum_list = [sum(elem) for elem in zip(*p)]
print(sum_list)
I'm trying to write a function that would combine two lists while removing duplicate items, but in a pure functional way.
For example:
a = [1,2,2]
b = [1,3,3,4,5,0]
union(a,b) --> [1,2,3,4,5,0]
The imperative form of the code would be:
def union(a,b):
c = []
for i in a + b:
if i not in c:
c.append(i)
return c
I've tried several approaches, but couldn't find a way to do that without using a loop to go over the items - what am I missing?
list(set(a + b))
This combines two lists a and b and using set takes only unique vales and then we can make it back to list.
If you want to keep the order you can use collections.OrderedDict, otherwise just use set. These data structures use hash values of their items for preserving them, thus they don't keep the duplicates.
In [11]: from collections import OrderedDict
In [12]: list(OrderedDict.fromkeys(a+b))
Out[12]: [1, 2, 3, 4, 5, 0]
Have you tried using sets?
>>> a = [1,2,2]
>>> b = [1,3,3,4,5,0]
>>> list(set(a).union(set(b)))
[0, 1, 2, 3, 4, 5]
To combine the two lists:
a = [1,2,2]
b = [1,3,3,4,5,0]
Using sets:
union = set(a) | set(b)
# -> set([0, 1, 2, 3, 4, 5])
Using comprehension list:
union = a + [x for x in b if x not in a]
# -> [1, 2, 2, 3, 3, 4, 5, 0]
Using loop, without duplicates, preserving order:
union = []
for x in a + b:
if x not in union:
union.append(x)
# -> [1, 2, 3, 4, 5, 0]
How about
>>> x = [1,2,3]
>>> y = [1,3,5,7,9]
>>> list(set(x).union(set(y)))
If you don't mind importing libraries use toolz for that (http://toolz.readthedocs.io/en/latest/index.html), which is generally a valuable and widely used helper for functional programming with Python. It has a function named unique (http://toolz.readthedocs.io/en/latest/api.html#toolz.itertoolz.unique), that does exactly what you want.
from toolz.itertoolz import unique
a = [1,2,2,3,0]
b = [1,3,3,4,5,0]
c = a + b # could do that with itertools.chain() in a more functional way
return list(unique(c))
# -> [1, 2, 3, 0, 4, 5]
I hope to write the join_lists function to take an arbitrary number of lists and concatenate them. For example, if the inputs are
m = [1, 2, 3]
n = [4, 5, 6]
o = [7, 8, 9]
then we I call print join_lists(m, n, o), it will return [1, 2, 3, 4, 5, 6, 7, 8, 9]. I realize I should use *args as the argument in join_lists, but not sure how to concatenate an arbitrary number of lists. Thanks.
Although you can use something which invokes __add__ sequentially, that is very much the wrong thing (for starters you end up creating as many new lists as there are lists in your input, which ends up having quadratic complexity).
The standard tool is itertools.chain:
def concatenate(*lists):
return itertools.chain(*lists)
or
def concatenate(*lists):
return itertools.chain.from_iterable(lists)
This will return a generator which yields each element of the lists in sequence. If you need it as a list, use list: list(itertools.chain.from_iterable(lists))
If you insist on doing this "by hand", then use extend:
def concatenate(*lists):
newlist = []
for l in lists: newlist.extend(l)
return newlist
Actually, don't use extend like that - it's still inefficient, because it has to keep extending the original list. The "right" way (it's still really the wrong way):
def concatenate(*lists):
lengths = map(len,lists)
newlen = sum(lengths)
newlist = [None]*newlen
start = 0
end = 0
for l,n in zip(lists,lengths):
end+=n
newlist[start:end] = list
start+=n
return newlist
http://ideone.com/Mi3UyL
You'll note that this still ends up doing as many copy operations as there are total slots in the lists. So, this isn't any better than using list(chain.from_iterable(lists)), and is probably worse, because list can make use of optimisations at the C level.
Finally, here's a version using extend (suboptimal) in one line, using reduce:
concatenate = lambda *lists: reduce((lambda a,b: a.extend(b) or a),lists,[])
One way would be this (using reduce) because I currently feel functional:
import operator
from functools import reduce
def concatenate(*lists):
return reduce(operator.add, lists)
However, a better functional method is given in Marcin's answer:
from itertools import chain
def concatenate(*lists):
return chain(*lists)
although you might as well use itertools.chain(*iterable_of_lists) directly.
A procedural way:
def concatenate(*lists):
new_list = []
for i in lists:
new_list.extend(i)
return new_list
A golfed version: j=lambda*x:sum(x,[]) (do not actually use this).
You can use sum() with an empty list as the start argument:
def join_lists(*lists):
return sum(lists, [])
For example:
>>> join_lists([1, 2, 3], [4, 5, 6])
[1, 2, 3, 4, 5, 6]
Another way:
>>> m = [1, 2, 3]
>>> n = [4, 5, 6]
>>> o = [7, 8, 9]
>>> p = []
>>> for (i, j, k) in (m, n, o):
... p.append(i)
... p.append(j)
... p.append(k)
...
>>> p
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>>
This seems to work just fine:
def join_lists(*args):
output = []
for lst in args:
output += lst
return output
It returns a new list with all the items of the previous lists. Is using + not appropriate for this kind of list processing?
Or you could be logical instead, making a variable (here 'z') equal to the first list passed to the 'join_lists' function
then assigning the items in the list (not the list itself) to a new list to which you'll then be able add the elements of the other lists:
m = [1, 2, 3]
n = [4, 5, 6]
o = [7, 8, 9]
def join_lists(*x):
z = [x[0]]
for i in range(len(z)):
new_list = z[i]
for item in x:
if item != z:
new_list += (item)
return new_list
then
print (join_lists(m, n ,o)
would output:
[1, 2, 3, 4, 5, 6, 7, 8, 9]
[(1,2), (2,3), (4,5), (3,4), (6,7), (6,7), (3,8)]
How do I return the 2nd value from each tuple inside this list?
Desired output:
[2, 3, 5, 4, 7, 7, 8]
With a list comprehension.
[x[1] for x in L]
Ignacio's answer is what you want. However, as someone also learning Python, let me try to dissect it for you... As mentioned, it is a list comprehension (covered in DiveIntoPython3, for example). Here are a few points:
[x[1] for x in L]
Notice the []'s around the line of code. These are what define a list. This tells you that this code returns a list, so it's of the list type. Hence, this technique is called a "list comprehension."
L is your original list. So you should define L = [(1,2),(2,3),(4,5),(3,4),(6,7),(6,7),(3,8)] prior to executing the above code.
x is a variable that only exists in the comprehension - try to access x outside of the comprehension, or type type(x) after executing the above line and it will tell you NameError: name 'x' is not defined, whereas type(L) returns <class 'list'>.
x[1] points to the second item in each of the tuples whereas x[0] would point to each of the first items.
So this line of code literally reads "return the second item in a tuple for all tuples in list L."
It's tough to tell how much you attempted the problem prior to asking the question, but perhaps you just weren't familiar with comprehensions? I would spend some time reading through Chapter 3 of DiveIntoPython, or any resource on comprehensions. Good luck.
A list comprehension is absolutely the way to do this. Another way that should be faster is map and itemgetter.
import operator
new_list = map(operator.itemgetter(1), old_list)
In response to the comment that the OP couldn't find an answer on google, I'll point out a super naive way to do it.
new_list = []
for item in old_list:
new_list.append(item[1])
This uses:
Declaring a variable to reference an empty list.
A for loop.
Calling the append method on a list.
If somebody is trying to learn a language and can't put together these basic pieces for themselves, then they need to view it as an exercise and do it themselves even if it takes twenty hours.
One needs to learn how to think about what one wants and compare that to the available tools. Every element in my second answer should be covered in a basic tutorial. You cannot learn to program without reading one.
You can also use sequence unpacking with zip:
L = [(1,2),(2,3),(4,5),(3,4),(6,7),(6,7),(3,8)]
_, res = zip(*L)
print(res)
# (2, 3, 5, 4, 7, 7, 8)
This also creates a tuple _ from the discarded first elements. Extracting only the second is possible, but more verbose:
from itertools import islice
res = next(islice(zip(*L), 1, None))
OR you can use pandas:
>>> import pandas as pd
>>> L = [(1,2),(2,3),(4,5),(3,4),(6,7),(6,7),(3,8)]
>>> df=pd.DataFrame(L)
>>> df[1]
0 2
1 3
2 5
3 4
4 7
5 7
6 8
Name: 1, dtype: int64
>>> df[1].tolist()
[2, 3, 5, 4, 7, 7, 8]
>>>
Or numpy:
>>> import numpy as np
>>> L = [(1,2),(2,3),(4,5),(3,4),(6,7),(6,7),(3,8)]
>>> arr=np.array(L)
>>> arr.T[1]
array([2, 3, 5, 4, 7, 7, 8])
>>> arr.T[1].tolist()
[2, 3, 5, 4, 7, 7, 8]
>>>
a = [(0,2), (4,3), (9,9), (10,-1)]
print(list(map(lambda item: item[1], a)))