with just four element getting the Memory error in python - python

I have been getting the memory error but unable to understand the reason behind that. Below is the code. Using the list and appending just two more elements in the list.
mylist = ['phonon', 'communication']
for i in mylist:
mylist.append(i.upper())
print(mylist)
It will be really very helpful if anyone can help me with that.

for i in mylist:
mylist.append(i.upper())
is basically appending to your list while iterating on it. So the iteration never ends.
You want to do:
mylist += [i.upper() for i in mylist]
in that last case, the right-hand expression is computed from a non-modified mylist, then its elements are appended to the existing mylist.
note that the above is equivalent to
mylist.extend([i.upper() for i in mylist])
or
mylist.extend(list(map(str.upper,mylist)))
note that for both snippets above it is necessary to convert to list, or you get the same memory error if the inside is lazily evaluated. The last snippet is probably the fastest because it doesn't use any python loops at all, map, and no lambda
For all 3 snippets the result is:
['phonon', 'communication', 'PHONON', 'COMMUNICATION']

I would add your edited elements to a new list:
uppers = []
for i in mylist:
uppers.append(i.upper())
print(uppers)

Building off Jean's answer:
mylist.extend(i.upper() for i in mylist)
Should give you the desired result.

Related

How to add up values of the "sublists" within a list of lists

I have a list of lists in my script:
list = [[1,2]
[4,3]
[6,2]
[1,6]
[9,2]
[6,5]]
I am looking for a solution to sum up the contents of each "sublist" within the list of lists. The desired output would be:
new_list = [3,7,8,7,11,11]
I know about combining ALL of these lists into one which would be:
new_list = [27,20]
But that's not what i'm looking to accomplish.
I need to combine the two values within these "sublists" and have them remain as their own entry in the main list.
I would also greatly appreciate it if it was also explained how you solved the problem rather than just handing me the solution. I'm trying to learn python so even a minor explanation would be greatly appreciated.
Using Python 3.7.4
Thanks, Riftie.
The "manual" solution will be using a for loop.
new_list = []
for sub_list in list:
new_list.append(sum(sub_list))
or as list compherension:
new_list = [sum(sub_list) for sub_list in list]
The for loop iterates through the elements of list. In your case, list is a list of lists. So every element is a list byitself. That means that while iterating, sub_list is a simple list. To get a sum of list I used sum() build-in function. You can of course iterate manually and sum every element:
new_list = []
for sub_list in list:
sum_val = 0
for element in sub_list:
sum_val = sum_val + element
new_list.append(sum_val)
but no need for that.
A better approach will be to use numpy, which allows you to sum by axis, as it looks on list of lists like an array. Since you are learning basic python, it's too soon to learn about numpy. Just keep in mind that there is a package for handling multi-dimensions arrays and it allows it perform some actions like sum on an axis by your choice.
Edit: I've seen the other solution suggest. As both will work, I believe this solution is more "accessible" for someone who learn to program for first time. Using list comprehension is great and correct, but may be a bit confusing while first learning. Also as suggested, calling your variables list is a bad idea because it's keyword. Better names will be "my_list", "tmp_list" or something else.
Use list comprehension. Also avoid using keywords as variable names, in your case you overrode the builtin list.
# a, b -> sequence unpacking
summed = [a + b for a, b in lst] # where lst is your list of lists
# if the inner lists contain variable number of elements, a more
# concise solution would be
summed2 = [sum(seq) for seq in lst]
Read more about the powerful list comprehension here.

List Comprehensions if else repeating element every three items

There are too many questions of list comprehensions on this website, but none seem to match what I'd like to do. I have already done it with a for loop, but I was wondering if it could be done with list comprehensions, or if someone could direct me where I could find a similar case.
I have a list of functions:
function_list=[iron,cobalt,nickel,copper,zinc,vanadium,chromium,managenese,titanium,footer]
Each function is a question I ask to my students, exported to a PDF file. The last function on the list, is footer which makes the PDF file insert a page skip to the next page.
So usually, What does a simple quiz look like (so far)?
call_functions([x for x in function_list[0:3]] + [function_list[-1]])
generating
call_functions([iron,cobalt,nickel,footer]) #as desired
where call_functions is basically a PDF exporter. So my list comprehension adds three questions and skips to the next page, adding three more. As the number of questions grow, the code ends up looking like a mess:
call_functions([x for x in function_list[0:3]] + [function_list[-1]] + [x for x in function_list[3:6]]+ [function_list[-1]] + [x for x in function_list[6:9]])
generating
call_functions([iron,cobalt,nickel,footer,copper,zinc,vanadium,footer,chromium,managenese,titanium]) #as desired
although this works, I'm trying to make a single comprehension list that will iterate through the list and after every third element, it'll insert the last element on the list. Or even keep footer outside the list is also viable. But I can't get it to work.
I've tried:
[x for i,x in enumerate(function_list[0:9]) if i%3==0 function_list[-1] else x]
to SyntaxError.
Also tried:
[x if i%3==0 function_list[-1] else x for i,x in enumerate(function_list[0:9])]
Also to SyntaxError
Could someone tell me (or direct me to) what am I doing wrong, and/or direct to a similar case, please?
Thanks
[func for i in range(0, len(function_list) - 1, 3) for func in function_list[i:i+3] + [function_list[-1]]]
output:
>>>
['iron',
'cobalt',
'nickel',
'footer',
'copper',
'zinc',
'vanadium',
'footer',
'chromium',
'managenese',
'titanium',
'footer']
Nevermind, I think I got it to work.
What worked for me was the following:
call_functions([x if (i+1)%4!=0 else function_list[-1] for i,x in enumerate(function_list)])
If I do
if i%4!=0 #making the fourth element function footer
I get a list that starts with the footer function. But doing:
if (i+1)%4!=0
I avoid the initial issue. I get:
call_functions([iron,cobalt,nickel,footer,copper,zinc,vanadium,footer,chromium,managenese,titanium,footer])
I'm sure there must be other ways to do this simpler and neater, any suggestions welcome.
Thanks!
Ex.

Append select dict keys to a list [duplicate]

I am trying to append objects to the end of a list repeatedly, like so:
list1 = []
n = 3
for i in range(0, n):
list1 = list1.append([i])
But I get an error like: AttributeError: 'NoneType' object has no attribute 'append'. Is this because list1 starts off as an empty list? How do I fix this error?
This question is specifically about how to fix the problem and append to the list correctly. In the original code, the reported error occurs when using a loop because .append returns None the first time. For why None is returned (the underlying design decision), see Why do these list operations return None, rather than the resulting list?.
If you have an IndexError from trying to assign to an index just past the end of a list - that doesn't work; you need the .append method instead. For more information, see Why does this iterative list-growing code give IndexError: list assignment index out of range? How can I repeatedly add elements to a list?.
If you want to append the same value multiple times, see Python: Append item to list N times.
append actually changes the list. Also, it takes an item, not a list. Hence, all you need is
for i in range(n):
list1.append(i)
(By the way, note that you can use range(n), in this case.)
I assume your actual use is more complicated, but you may be able to use a list comprehension, which is more pythonic for this:
list1 = [i for i in range(n)]
Or, in this case, in Python 2.x range(n) in fact creates the list that you want already, although in Python 3.x, you need list(range(n)).
You don't need the assignment operator. append returns None.
append returns None, so at the second iteration you are calling method append of NoneType. Just remove the assignment:
for i in range(0, n):
list1.append([i])
Mikola has the right answer but a little more explanation. It will run the first time, but because append returns None, after the first iteration of the for loop, your assignment will cause list1 to equal None and therefore the error is thrown on the second iteration.
I personally prefer the + operator than append:
for i in range(0, n):
list1 += [[i]]
But this is creating a new list every time, so might not be the best if performance is critical.
Note that you also can use insert in order to put number into the required position within list:
initList = [1,2,3,4,5]
initList.insert(2, 10) # insert(pos, val) => initList = [1,2,10,3,4,5]
And also note that in python you can always get a list length using method len()
Like Mikola said, append() returns a void, so every iteration you're setting list1 to a nonetype because append is returning a nonetype. On the next iteration, list1 is null so you're trying to call the append method of a null. Nulls don't have methods, hence your error.
use my_list.append(...)
and do not use and other list to append as list are mutable.

how can i append in reverse? python

.append
Function adds elements to the list.
How can I add elements to the list? In reverse? So that index zero is new value, and the old values move up in index?
What append does
[a,b,c,d,e]
what I would like.
[e,d,c,b,a]
Thank you very much.
Suppose you have a list a, a = [1, 2, 3]
Now suppose you wonder what kinds of things you can do to that list:
dir(a)
Hmmmm... wonder what this insert thingy does...
help(a.insert)
Insert object before index, you say? Why, that sounds a lot like what I want to do! If I want to insert something at the beginning of the list, that would be before index 0. What object do I want to insert? Let's try 7...
a.insert(0, 7)
print a
Well, look at that 7 right at the front of the list!
TL;DR: dir() will let you see what's available, help() will show you how it works, and then you can play around with it and see what it does, or Google up some documentation since you now know what the feature you want is called.
It would be more efficient to use a deque(double-ended queue) for this. Inserting at index 0 is extremely costly in lists since each element must be shifted over which requires O(N) running time, in a deque the same operation is O(1).
>>> from collections import deque
>>> x = deque()
>>> x.appendleft('a')
>>> x.appendleft('b')
>>> x
deque(['b', 'a'])
Use somelist.insert(0, item) to place item at the beginning of somelist, shifting all other elements down. Note that for large lists this is a very expensive operation. Consider using deque instead if you will be adding items to or removing items from both ends of the sequence.
Using Python's list insert command with 0 for the position value will insert the value at the head of the list, thus inserting in reverse order:
your_list.insert(0, new_item)
You can do
your_list=['New item!!']+your_list
But the insert method works as well.
lst=["a","b","c","d","e","f"]
lst_rev=[]
lst_rev.append(lst[::-1])
print(lst_rev)
Here's an example of how to add elements in a list in reverse order:
liste1 = [1,2,3,4,5]
liste2 = list()
for i in liste1:
liste2.insert(0,i)
Use the following (assuming x is what you want to prepend):
your_list = [x] + your_list
or:
your_list.insert(0, x)

Modifying list while iterating [duplicate]

This question already has answers here:
Strange result when removing item from a list while iterating over it
(8 answers)
Closed 7 years ago.
l = range(100)
for i in l:
print i,
print l.pop(0),
print l.pop(0)
The above python code gives the output quite different from expected. I want to loop over items so that I can skip an item while looping.
Please explain.
Never alter the container you're looping on, because iterators on that container are not going to be informed of your alterations and, as you've noticed, that's quite likely to produce a very different loop and/or an incorrect one. In normal cases, looping on a copy of the container helps, but in your case it's clear that you don't want that, as the container will be empty after 50 legs of the loop and if you then try popping again you'll get an exception.
What's anything BUT clear is, what behavior are you trying to achieve, if any?! Maybe you can express your desires with a while...?
i = 0
while i < len(some_list):
print i,
print some_list.pop(0),
print some_list.pop(0)
I've been bitten before by (someone else's) "clever" code that tries to modify a list while iterating over it. I resolved that I would never do it under any circumstance.
You can use the slice operator mylist[::3] to skip across to every third item in your list.
mylist = [i for i in range(100)]
for i in mylist[::3]:
print(i)
Other points about my example relate to new syntax in python 3.0.
I use a list comprehension to define mylist because it works in Python 3.0 (see below)
print is a function in python 3.0
Python 3.0 range() now behaves like xrange() used to behave, except it works with values of arbitrary size. The latter no longer exists.
The general rule of thumb is that you don't modify a collection/array/list while iterating over it.
Use a secondary list to store the items you want to act upon and execute that logic in a loop after your initial loop.
Use a while loop that checks for the truthfulness of the array:
while array:
value = array.pop(0)
# do some calculation here
And it should do it without any errors or funny behaviour.
Try this. It avoids mutating a thing you're iterating across, which is generally a code smell.
for i in xrange(0, 100, 3):
print i
See xrange.
I guess this is what you want:
l = range(100)
index = 0
for i in l:
print i,
try:
print l.pop(index+1),
print l.pop(index+1)
except IndexError:
pass
index += 1
It is quite handy to code when the number of item to be popped is a run time decision.
But it runs with very a bad efficiency and the code is hard to maintain.
This slice syntax makes a copy of the list and does what you want:
l = range(100)
for i in l[:]:
print i,
print l.pop(0),
print l.pop(0)

Categories

Resources