Let's say
>>> a = [1,2,3,4,5]
And I want an output like
>>> b
[[1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4, 5]]
Here is my code:
class Child(object):
def get_lines(self):
a = [1,2,3,4,5]
b=[]
c=[]
j=0
for i in a:
print i
b.append(i)
print b
c.insert(j,b)
j=j+1
print c
son= Child()
son.get_lines()
When I print list b in loop, it gives:
1
[1]
2
[1, 2]
3
[1, 2, 3]
4
[1, 2, 3, 4]
5
[1, 2, 3, 4, 5]
and the output is:
[[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]]
Where do I make wrong in the code?
b is always the same list object (note I've changed print c to return c):
>>> map(id, Child().get_lines())
...
[49021616, 49021616, 49021616, 49021616, 49021616]
c contains five references to the same list. I think what you want is:
class Child(object):
def get_lines(self):
a = [1, 2, 3, 4, 5]
return [a[:x+1] for x in range(len(a))]
This makes a shallow copy of part (or all) of a for each step:
>>> Child().get_lines()
[[1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4, 5]]
Replace:
c.insert(j,b)
with:
c.append(b[:])
and try again.
You need to make a copy of b. Otherwise you add the same b again and again resulting in the full list at all indices. 'b[:]' copies the list.
This solution does the same but is a bit shorter:
a = [1, 2, 3, 4, 5]
c = []
for i in range(1, len(a) + 1):
c.append(a[:i])
now c is:
[[1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4, 5]]
a[:i] slices the list a from the beginning to excluding the index i.
In this case it does a[:1], a[:2] and so on. a[:1] makes a new list [1],
a[:2] a new list [1, 2,] and so on. Using append() is simpler and insert().
Another alternative is a list comprehension:
a = [1, 2, 3, 4, 5]
[a[:i] for i in range(1, len(a) + 1)]
also results in:
[[1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4, 5]]
Here in this case you are not supposed to append value to the list object (b).
since list is mutable, it will refer to the exact same object in memory until a reassign occurs.
>>> b=[]
>>> b.append(1)
>>> id(b)
4337935424
>>> b.append(2)
>>> id(b)
4337935424
>>> b.append(3)
>>> id(b)
4337935424
>>> b = [1, 2, 3, 4]
>>> id(b)
4337942608
so that in your code c will make five references to the same list.
It will instruct a new object and then (to the extent possible) inserts references into it to the objects found in the original.
>>> class Child(object):
...
... def get_lines(self):
... a = [1, 2, 3, 4, 5]
... return map(lambda x: a[:x+1], range(len(a)))
...
>>> Child().get_lines()
[[1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4, 5]]
You insert same b five times in list c. As a list actually contains references to objects and not copies, you have 5 times a reference to a same b list in which you have added successively 1, 2, 3, 4, 5. So the result.
You must instead add copies of list b :
def get_lines(self):
a = [1,2,3,4,5]
b=[]
c=[]
j=0
for i in a:
print i
b.append(i)
print b
c.insert(j,b[:]) # forces insertion of a copy
j=j+1
print c
In the loop, value of b persists since it's a mutable object. Hence when you print c, the last value of b is shown.
Instead of using b as temporary variable, you can directly use a as follows:
class Child(object):
def get_lines(self):
a = [1,2,3,4,5]
b = []
for index, element in enumerate(a, 1):
b.append(x[:index])
return b
son= Child()
son.get_lines()
Related
In python,
y = [1,2,3,4]
[1,2,3,4]
[1,2,3,4]
[1,2,3,4]
Notice that y contains four lines of lists, and it is not a matrix.
What I am trying to do is to add last columns of fours and output:
[1,2,3,16]
Let us suppose that you have list of lists:
y = [[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]]
res = y[0][:3] + [sum(el[3] for el in y)]
print res
>>> [1, 2, 3, 16]
i really need your help with slicing a list.
lets say I've got a list of lists like this:
field=[[1, 2, 4, 4], [4, 1, 4, 2], [2, 1, 4, 3], [2, 4, 2, 3], [1, 2, 3, 4]]
and I have to write a function which will return a string that will look like this:
42334
44423
21142
14221
thus fat i managed to do this:
def out(field):
b=''
for list in field:
list1=list[::-1]
b+=''.join((str(sth) for sth in list1))+'\n'
return b
which returns this:
4421
2414
3412
3242
4321
You need to transpose your list of rows to a list of columns, as well as reverse the results of the transposition to get a proper rotation.
zip(*field) transposes the rows to columns, reversed() then reverses the results. Combined with a list comprehension you can do this all in one expression:
def out(field):
return '\n'.join([''.join(map(str, c)) for c in reversed(list(zip(*field)))])
or spelled out into an explicit loop:
def out(field):
b = []
for columns in reversed(list(zip(*field))):
b.append(''.join(map(str, columns)))
return '\n'.join(b)
The list() call around the zip() call allows us to reverse the iterator result in Python 3; it can be dropped in Python 2.
Demo:
>>> field=[[1, 2, 4, 4], [4, 1, 4, 2], [2, 1, 4, 3], [2, 4, 2, 3], [1, 2, 3, 4]]
>>> [''.join(map(str, c)) for c in reversed(list(zip(*field)))]
['42334', '44423', '21142', '14221']
>>> '\n'.join([''.join(map(str, c)) for c in reversed(list(zip(*field)))])
'42334\n44423\n21142\n14221'
>>> print('\n'.join([''.join(map(str, c)) for c in reversed(list(zip(*field)))]))
42334
44423
21142
14221
def out(field):
b=''
a=[]
while len(field[0])>0:
for list in field:
a.append(list.pop())
a.append("\n")
a="".join(str(x) for x in a)
return a
x=[[1, 2, 4, 4], [4, 1, 4, 2], [2, 1, 4, 3], [2, 4, 2, 3], [1, 2, 3, 4]]
print out(x)
This question already has answers here:
How to group a list of tuples/objects by similar index/attribute in python?
(3 answers)
Closed 8 years ago.
I see splitting-a-list-of-arbitrary-size-into-only-roughly-n-equal-parts. How about not-equal splitting? I have list having items with some attribute (value which can be retrieved for running same function against every item), how to split items having same attribute to be new list e.g. new sublist? Something lambda-related could work here?
Simple example could be:
list = [1, 1, 1, 2, 3, 3, 3, 3, 4, 4]
After fancy operation we could have:
list = [[1, 1, 1], [2], [3, 3, 3, 3], [4, 4]]
>>> L = [1, 1, 1, 2, 3, 3, 3, 3, 4, 4]
>>> [list(g) for i, g in itertools.groupby(L)]
[[1, 1, 1], [2], [3, 3, 3, 3], [4, 4]]
>>> L2 = ['apple', 'aardvark', 'banana', 'coconut', 'crow']
>>> [list(g) for i, g in itertools.groupby(L2, operator.itemgetter(0))]
[['apple', 'aardvark'], ['banana'], ['coconut', 'crow']]
You should use the itertools.groupby function from the standard library.
This function groups the elements in the iterable it receives (by default using the identity function, i.e., checking consequent elements for equality), and for each streak of grouped elements, it reutrns a 2-tuple consisting of the streak representative (the element itself), and an iterator of the elements within the streak.
Indeed:
l = [1, 1, 1, 2, 3, 3, 3, 3, 4, 4]
list(list(k[1]) for k in groupby(l))
>>> [[1, 1, 1], [2], [3, 3, 3, 3], [4, 4]]
P.S. you should avoid using list as a variable name, as it would conflict with the built-in type/function.
Here's a pretty simple roll your own solution. If the 'attribute' in question is simply the value of the item, there are more straightforward approaches.
def split_into_sublists(data_list, sizes_list):
if sum(sizes_list) != len(data_list):
raise ValueError
count = 0
output = []
for size in sizes_list:
output.append(data_list[count:count+size])
count += size
return output
if __name__ == '__main__':
data_list = [1, 1, 1, 2, 3, 3, 3, 3, 4, 4]
sizes_list = [3,1,4,2]
list2 = [[1, 1, 1], [2], [3, 3, 3, 3], [4, 4]]
print(split_into_sublists(data_list, sizes_list) == list2) # True
I am trying to expand sublists within a list. I wrote it for one layer of sublists within the list. Is there a better way to code this so to scale for arbitrary number of nested lists? See example as follows:
a = [1, 2, 3]
b = [4, 5, 6]
c = [a, b]
def expand(x):
# expands a list of lists with no further sublists
a = []
for i in x:
# could also here do a += i and avoid the second for loop
for j in i:
a.append(j)
return a
print expand(c)
Returns the desired [1, 2, 3, 4, 5, 6]
To further clarify, I am wondering how to better scale for
`e = [c, a, b]' and further nested iterations.
c = [[1, 2, 3], [4, 5, 6]]
# first method
res = [x for lst in c for x in lst]
# second method
from itertools import chain
res = list(chain(*c))
Edit: he wants iteratively nested lists!
c = [[[1], [2, 3]], [4, 5], [[6, 7, 8], 9]]
def expand(lst):
try:
for a in lst:
for b in expand(a):
yield b
except TypeError:
yield lst
res = list(expand(c)) # => [1, 2, 3, 4, 5, 6, 7, 8, 9]
Use Recursion:
def flat_list(l):
for a in l:
if isinstance(a, list):
for x in flat_list(a):
yield x
else:
yield a
a = [1, 2, 3]
b = [4, 5, 6]
c = [a, b]
e = [c, a, b]
print list(flat_list(c))
print list(flat_list(e))
the output is:
[1, 2, 3, 4, 5, 6]
[1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6]
One solution:
def flatten(ls):
result = []
stack = [ls]
while stack:
if isinstance(stack[-1], list):
try: stack.append(stack[-1].pop(0))
except IndexError: stack.pop() # remove now-empty sublist
else:
result.append(stack.pop())
return result
a = [1, 2, 3]
b = [4, 5, 6]
c = [a, b]
e = [c, a, b]
print flatten(e)
Output:
[1, 2, 3, 4, 5, 6]
Or :
Using sum:
>>> e
[[[1, 2, 3], [4, 5, 6]], [1, 2, 3], [4, 5, 6]]
>>> sum(e[0], [])
[1, 2, 3, 4, 5, 6]
Using reduce:
>>> reduce(lambda x,y: x+y, e[0])
[1, 2, 3, 4, 5, 6]
>>>
I'm working on a project and I need to repeat a list within a list a certain number of times. Obviously, L.append(L) just adds the elements again without creating separate lists. I'm just stumped on how to make the lists separate within the big list.
In short form, this is what I have:
L = [1,2,3,4,5]
If I wanted to to repeat it, say, 3 times so I'd have:
L = [[1,2,3,4,5],[1,2,3,4,5],[1,2,3,4,5]]
How do I achieve this? I'm looking for lists within the big list.
No need for any functions:
>>> L = [1,2,3,4,5]
>>> [L]*3
[[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]]
However, you should note that if you change one value in any of the lists, all the others will change because they reference the same object.
>>> mylist = [L]*3
>>> mylist[0][0] = 6
>>> print mylist
[[6, 2, 3, 4, 5], [6, 2, 3, 4, 5], [6, 2, 3, 4, 5]]
>>> print L
[6, 2, 3, 4, 5]
To avoid this:
>>> L = [1,2,3,4,5]
>>> mylist = [L[:] for _ in range(3)]
>>> mylist[0][0] = 6
>>> print L
[1, 2, 3, 4, 5]
>>> print mylist
[[6, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]]
Notice how L didn't change, and only the first list in mylist changed.
Thanks everyone in the comments for helping :).