Processing a list of lists - python

I have a list of lists, say:
arr = [[1, 2], [1, 3], [1, 4]]
I would like to append 100 to each of the inner lists. Output for the above example would be:
arr = [[1, 2, 100], [1, 3, 100], [1, 4, 100]]
I can of course do:
for elem in arr:
elem.append(100)
But is there something more pythonic that can be done? Why does the following not work:
arr = [elem.append(100) for elem in arr]

The second version should be written like arr = [elem + [100] for elem in arr]. But the most pythonic way if you ask me is the first one. The for construct has it's own use, and it suits very well here.

Note that your code also works - the only thing you have to know is that there is no need to assign result to variable in such a case:
arr = [[1, 2], [1, 3], [1, 4]]
[x.append(100) for x in arr]
After execution arr will contain updated list [[1, 2, 100], [1, 3, 100], [1, 4, 100]], e.g it work like in-place update, but this not very common practice to do this.
The same result you will get in the next case:
map(lambda x: x.append(100), arr)
As was discussed you can use list comprehension or map to do this with assigning result to any variable:
res = map(lambda x: x + [100], arr)

You can do
[a + [100] for a in arr]
The reason why your append doesn't work is that append doesn't return the list, but rather None.
Of course, this is more resource intensive than just doing append - you end up making copies of everything.

This is the more pythonic way
for elem in arr:
elem.append(100)
but as an option you can also try this:
[arr[i].append(100) for i in range(len(arr))]
print arr # It will return [[1, 2, 100], [1, 3, 100], [1, 4, 100]]

Related

Nested list - create new nested list with indices as items

I would like to create a new nested list from an already existing nested list. This new list should include the indices+1 from the existing list.
Example:
my_list = [[20, 45, 80],[56, 29],[76],[38,156,11,387]]
Result:
my_new_list = [[1,2,3],[1,2],[1],[1,2,3,4]]
How can I create such a list?
save a python loop, force iteration of range (required for python 3) in a list comprehension, so it's faster than a classical double nested comprehension:
my_list = [[20, 45, 80],[56, 29],[76],[38,156,11,387]]
index_list = [list(range(1,len(x)+1)) for x in my_list]
There's a few ways to do this, but the first that comes to mind is to enumerate the elements with a starting index of 1 in a nested list comprehension.
>>> [[index for index, value in enumerate(sub, 1)] for sub in my_list]
[[1, 2, 3], [1, 2], [1], [1, 2, 3, 4]]
Another solution could be:
new_list = [list(range(1,len(item)+1)) for item in my_list]
Here is are some simple solutions:
>>> lst = [[20, 45, 80],[56, 29],[76],[38,156,11,387]]
>>> out = [[x+1 for x,_ in enumerate(y)] for y in lst]
>>> out
[[1, 2, 3], [1, 2], [1], [1, 2, 3, 4]]
>>>
>>>
>>> out = [[x+1 for x in range(len(y))] for y in lst]
>>> out
[[1, 2, 3], [1, 2], [1], [1, 2, 3, 4]]
Using nested list comprehension
First you want a list with every number from 1 to the length of your sublist. There are several ways to do this with list comprehension.
For example
[i for i in range(1, len(sublist) + 1)]
or
[i + 1 for i in range(len(sublist))]
Second you want to do this for every sublist inside your my_list. Therefore you have to use nested list comprehension:
>>> my_list = [[20, 45, 80],[56, 29],[76],[38,156,11,387]]
>>> my_new_list = [[i+1 for i in range(len(sublist))] for sublist in my_list]
>>> my_new_list
[[1, 2, 3], [1, 2], [1], [1, 2, 3, 4]]
Using list comprehension with range
Another way would be using the range built-in function as a generator for your sublists:
>>> [list(range(1, len(sublist) + 1)) for sublist in my_list]
[[1, 2, 3], [1, 2], [1], [1, 2, 3, 4]]
Using map with range
Or you can use the map built-in function
>>> list(map(
... lambda sublist: list(range(1, len(sublist) + 1)),
... my_list
... ))
[[1, 2, 3], [1, 2], [1], [1, 2, 3, 4]]

List comprehensions

I have a for loop for outputting values into a list.
This is my output:
[[23, 34, 34] [34,21,34,56] [21,3,5,67]]
Below is my code that works for the above output:
y_train = ([[word2index[w] for w in sent[1:]] for sent in tokenized_sentences]).
But I would like to append a value at the end of each smaller list. How can I modify my code to handle this? My desired output should look like this:
[[23,34,34,**2**][34,21,34,56,**2**][21,3,5,67,**2**]]
so I would like to append a new value at the end of each inner list.
P.S. A normal for loop handling this would be good too.
for x in y_train:
x.append(element)
example:
>>> listOfLists = [[1,2], [2,3], [4,5]]
>>> for x in listOfLists:
... x.append(2)
>>> listOfLists
[[1, 2, 2], [2, 3, 2], [4, 5, 2]]

Convert nested iterables to list

Is there an easy way in python (using itertools, or otherwise) to convert a nested iterable f into its corresponding list or tuple? I'd like to save f so I can iterate over it multiple times, which means that if some nested elements of f are generators, I'll be in trouble.
I'll give an example input/output.
>>> g = iter(range(2))
>>> my_input = [1, [2, 3], ((4), 5), [6, g]]
>>> magical_function(my_input)
[1, [2, 3], [[4], 5], [6, [0, 1]]]
It would be fine if the output consisted of tuples, too. The issue is that iterating over g "consumes" it, so it can't be used again.
This seems like it would be best to do by checking if each element is iterable, and calling a recursive function over it if it is iterable. Just as a quick draw-up, I would try something like:
import collections
g = iter(range(2))
my_input = [1, [2, 3], ((4), 5), [6, g]]
def unfold(iterable):
ret = []
for element in iterable:
if isinstance(element, collections.Iterable):
ret.append(unfold(element))
else:
ret.append(element)
return ret
n = unfold(my_input)
print(n)
print(n)
which returns
$ python3 so.py
[1, [2, 3], [4, 5], [6, [0, 1]]]
[1, [2, 3], [4, 5], [6, [0, 1]]]
It's not the prettiest way, and you can find ways to improve it (it puts everything in a list instead of preserving tuples), but here is the general idea I would use.

Adding elements to List using a comprehension

Lets say I have a list:
List = [1,2,3,4,5]
I want to use a comprehension to output a list of lists for every element, let's say i, in "List" containing 1,2,...,i. So the comprehension would output:
[[1],[1,2],[1,2,3],[1,2,3,4],[1,2,3,4,5]]
The same would work for a List of List = [1,3,5] where the output would be:
[[1],[1,2,3],[1,2,3,4,5]
I do not want to use any modules like numpy or itertools
Any help would me much appreciated!
Sure:
>>> [range(1, i+1) for i in List]
[[1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4, 5]]

Python, working with list comprehensions

I have such code:
a = [[1, 1], [2, 1], [3, 0]]
I want to get two lists, the first contains elements of 'a', where a[][1] = 1, and the second - elements where a[][1] = 0. So
first_list = [[1, 1], [2, 1]]
second_list = [[3, 0]].
I can do such thing with two list comprehension:
first_list = [i for i in a if i[1] == 1]
second_list = [i for i in a if i[1] == 0]
But maybe exists other (more pythonic, or shorter) way to do this? Thanks for your answers.
List comprehension are very pythonic and the recommended way of doing this. Your code is fine.
If you want to have it in a single line you could do something like
first_list, second_list = [i for i in a if i[1] == 1], [i for i in a if i[1] == 0]
Remember that, "Explicit is better than implicit."
Your code is fine
You can use sorted() and itertools.groupby() to do this, but I don't know that it would qualify as Pythonic per se:
>>> dict((k, list(v)) for (k, v) in itertools.groupby(sorted(a, key=operator.itemgetter(1)), operator.itemgetter(1)))
{0: [[3, 0]], 1: [[1, 1], [2, 1]]}
what about this,
In [1]: a = [[1, 1], [2, 1], [3, 0]]
In [2]: first_list = []
In [3]: second_list = []
In [4]: [first_list.append(i) if i[1] == 1 else second_list.append(i) for i in a]
Out[4]: [None, None, None]
In [5]: first_list, second_list
Out[5]: ([[1, 1], [2, 1]], [[3, 0]])
instead of two sublist, I prefer dict (or defaultdict, OrderedDict, Counter, etc.)
In [6]: from collections import defaultdict
In [7]: d = defaultdict(list)
In [8]: [d[i[1]].append(i) for i in a]
Out[8]: [None, None, None]
In [9]: d
Out[9]: {0: [[3, 0]], 1: [[1, 1], [2, 1]]}
If the lists are reasonably short then two list comprehensions will do fine: you shouldn't be worried about performance until your code is all working and you know it is too slow.
If your lists are long or the code runs often and you have demonstrated that it is a bottleneck then all you have to do is switch from list comprehensions to a for loop:
first_list, second_list = [], []
for element in a:
if element[1] == 1:
first_list.append(element)
else:
second_list.append(element)
which is both clear and easily extended to more cases.
list comprehensions are great. If you want slightly more simple code (but slightly longer) then just use a for loop.
Yet another option would be filters and maps:
a = [[1, 1], [2, 1], [3, 0]]
g1=filter(lambda i: i[1]==1,a)
g1=map(lambda i: i[0],g1)
g2=filter(lambda i: i[1]==0,a)
g2=map(lambda i: i[0],g2)
print g1
print g2

Categories

Resources