Python 3 Error Missunderstanding (IndexError) - python

Here's my code
def abc(l,z):
L=[]
länge= len(L)
for x in range(0, länge+1):
L[x]+z
print(L)
abc(["1","2","3"],"-")
I want the program to output "1-2-3"
l in abc(l,z) should be a List out of Strings which combines "l" and "z" to a single String.
I'm getting an Index Error: list index out of range.

There are a couple of issues here.
First, range(0, länge+1) will stop at länge but your list only has indexes from 0 tolänge - 1, so that's one source for an IndexError.
Second, L[x]+z will give you another IndexError because L is empty but you try to access L[0] (and in the next iteration, where you don't get because of the error, L[1], L[2], and so on).
Third, even without an IndexError the statement L[x]+z will do nothing. You compute the value of L[x]+z but then you don't assign any variable to it, so it is immediately lost.
Fourth, in order to print your final result, put the call to print after the for loop, not inside. Consider using return instead of print if you actually want to do something with the result the function produces (make sure to educate yourself on the difference between print and return).
Fifth, you want to build a string, so the usage of the list L does not make much sense. Start with an empty string and add the current item from l and z to it in the loop body (coupled with a re-assignment in order to not lose the freshly computed value).
Lastly, there's no point in using range here. You can iterate over values in a list direclty by simply writing for x in l:.
That should give you enough to work with and fix your code for now.
(If you don't care why your function does not work and this is not an exercise, simply use str.join as suggested in the comments.)

Related

Question about an attempt to print all permutations of a given list

I just wanted to find out what is the reason that the python shell doesn't give the output i expect for the following recursive code:
def permutator(list,track):
if len(list)==1:
track.append(list[0])
print (track)
else:
for n in range(len(list)):
track.append(list[n])
return permutator(list[:n]+list[n+1:],track)
I expect this script to print all permutations of a given list when the variable ''track'' is initiallized as an empty list ([]); for example, i expected permutator([1,2],[]) to print [1,2] and [2,1]. But it prints only [1,2]... and it really dissapointed me, since it took me a lot of time to concieve of the idea to treat the permutator function as function of two variable instead of one, in such a way that the track "documents" the recursion process (the sequential iterative process) until one arrives at a permutation of the original list.
So what is my mistake? is it fundamental (so the whole idea of the code is wrong...) or maybe there is only a small variation i need to do in order for it to start working?
I really tried to achieve success on this problem on my own but i have given up, so every help will be blessed!
When you return the function ends and the rest of the loop never executes. Also, you don't want to append to the list becuase that effects the list that gets passed to the functions called later - instead just pass the list as it would be after appending as an argument. Specifically here, since you just want to print values, there's no need to return, so you can do:
def permutator(list,track):
if len(list)==1:
track.append(list[0])
print (track)
else:
for n in range(len(list)):
permutator(list[:n]+list[n+1:],track + [list[n]])
If you decide you want to return all permutations instead of printing them, the change is easy enough:
def permutator(list,track):
if len(list)==1:
return track + [list[0]]
else:
perms = []
for n in range(len(list)):
perms.append(permutator(list[:n]+list[n+1:],track + [list[n]]))
return perms

How to keep on updating a specific list within the for loop?

I'm very new to the world of programming, I've been trying to solve a specific python academic exercise but I ran into an obstacle.
The problem is that I need to generate a lucky numbers sequence, as in the user inputs a sequence [1,...,n] and these steps happen:
Every second element is removed
Every third element is removed
Every fourth element is removed
.
.
.
When it becomes impossible to remove more numbers, the numbers left in the list are "lucky".
This is my code:
def lucky(l):
index = 2
new_list = []
while(index<len(l)):
for i in range(len(l)):
if(i%index==0):
new_list.append(l[i])
index=index+1
return new_list
The while loop is to have the final condition when " it is impossible to remove more numbers". However with every iteration, the list gets shorter more and more, but I don't know how to do it.
My code works for the first condition when index=2(remove every 2nd element), then in the following loops it doesn't work because:
It is still limited by length of the original list.
new_list.append(l[i]) will just add more elements to the new_list, rather than updating it in its place.
I don't know how to update the list without creating multiple amounts of lists and with each iteration adding the new elements to a new list.
Any help is appreciated.
You could use del with appropriate list slicing (see the manual for more details) to update the list in-place:
def lucky(l):
interval = 2
while interval <= len(l):
del l[interval-1::interval]
interval += 1
I am not sure if I understand your question correctly, but you can remove items from your original list via del l[index], where index is the index of the element to be removed.
For more details on lists look here:
https://docs.python.org/3/tutorial/datastructures.html
import math
def lucky(l, index):
for i in range(math.floor(len(l)/index)):
del l[(i+1)*(index-1)]
Not sure if the code will work, as I cannot test it right now. But I think it should work somehow like that.
EDIT:
Tested it and the code works. If you want to run all three steps, just do:
l = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
lucky(l,2)
lucky(l,3)
lucky(l,4)
print(l)
>>>[1,3,7,13,15]

How to join multiple rows into single line using python? [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.

Delete elements of a List, using a condition

Hello I'm learning to program in Python to manipulate data bases and I can't make this simple task. Please someone help me.
I have this list
CIS=['4998200lp','2159140lp','02546or']
I want to get this result:
CIS=['4998200lp','2159140lp','2546or']
I was trying something like:
for x in CIS:
izq= x[:1]
if izq == 0:
CIS=[x.replace(x[:1],'') for x in CIS]
print (CIS)
I just want to delete the first element of every string for the condition izq == 0.
Your description doesn't match your example input/output which also differs from your code.
Based on the example input/output, I suspect what you're trying to do is strip a single leading 0 from any string that starts with 0. And that's not too bad, but you can't do it in a for loop without having an index to assign back to. For that, you can use enumerate:
for i, x in enumerate(CIS):
if x.startswith('0'): # or x[:1] == '0' if you really prefer
CIS[i] = x[1:]
Alternatively, you can use a list comprehension to replace CIS:
CIS = [x[1:] if x.startswith('0') else x for x in CIS]
and to mutate in place (rather than making a new list), use the same comprehension but assign to the full slice, which makes it behave like the spelled out loop in the first example:
CIS[:] = [x[1:] if x.startswith('0') else x for x in CIS]
The difference between examples #1/#3 and example #2 occurs if CIS was passed as an argument to a function, or otherwise is referenced in multiple places. In #1/#3, it's mutating the list in place, so all references will see the updates, in #2, it's reassigning CIS, but leaving the original list unchanged; if other references exist, they won't appear changed.
Note: If the goal is to remove all leading 0s, then use str.lstrip, e.g.:
CIS = [x.lstrip('0') for x in CIS]
with similar adaptations for the other approaches. You don't even need to test for the presence of 0 in that case, as lstrip will return the str unmodified if it doesn't begin with 0.
If you are simply looking to remove the first zero of every string, utilize the startswith method. Also, don't look for an integer 0. Look for a string '0'.
Finally, you can simplify your implementation with doing this all in a comprehension, creating a new list with your new data:
[w[1:] if w.startswith('0') else w for w in CIS]
Outputs:
['4998200lp', '2159140lp', '2546or']
Just try to delete first character of every elements that starts with 0:
CIS=['4998200lp','2159140lp','02546or']
for i,v in enumerate(CIS):
if v.startswith('0'):
CIS[i] = v[1:]
CIS # ['4998200lp', '2159140lp', '2546or']
Actually your loop contained a very close approach to a working solution:
CIS=['4998200lp','2159140lp','02546or']
CIS=[x.replace(x[:1],'') for x in CIS]
but this would strip all first elements. To only replace them if they are '0' (notice that's not the same as the integer: 0) you need to incorporate you if ... else ... into the list-comprehension:
CIS=['4998200lp','2159140lp','02546or']
CIS=[x.replace(x[:1],'',1) if x[:1] == '0' else x for x in CIS ]
The if ... else ... syntax might be a bit strange but just try to read the code aloud: "Insert the replaced x if the first character is a zero or if not insert x, for every x in CIS".
The other answers contain much more sophisticated approaches but I just wanted to add this answer to give you a heads-up that you were on the right track!
But it's generally a bad idea to use a list-comprehension inside a for loop if they iterate over the same iterable. Mostly you just want one of them.

Altering a list using append during a list comprehension

Caveat: this is a straight up question for code-golfing, so I know what I'm asking is bad practise in production
I'm trying to alter an array during a list comprehension, but for some reason it is hanging and I don't know why or how to fix this.
I'm dealing with a list of lists of indeterminite depth and need to condense them to a flat list - for those curious its this question. But at this stage, lets just say I need a flat list of all the elements in the list, and 0 if it is a list.
The normal method is to iterate through the list and if its a list add it to the end, like so:
for o in x:
if type(o)==type([]):x+=o
else:i+=o
print i
I'm trying to shorten this using list comprehension, like so.
print sum([
[o,x.append(o) or 0][type(o)==type([])]
for o in x
]))
Now, I know List.append returns None, so to ensure that I get a numeric value, lazy evaluation says I can do x.append(o) or 0, and since None is "falsy" it will evaulate the second part and the value is 0.
But it doesn't. If I put x.append() into the list comprehension over x, it doesn't break or error, or return an iteration error, it just freezes. Why does append freeze during the list comprehension, but the for loop above works fine?
edit: To keep this question from being deleted, I'm not looking for golfing tips (they are very educational though), I was looking for an answer as to why the code wasn't working as I had written it.
or may be lazy, but list definitions aren't. For each o in x, when the [o,x.append(o) or 0][type(o)==type([])] monstrosity is evaluated, Python has to evaluate [o,x.append(o) or 0], which means evaluating x.append(o) or 0, which means that o will be appended to x regardless of whether it's a list. Thus, you end up with every element of x appended to x, and then they get appended again and again and again and OutOfMemoryError
What about:
y = [element for element in x if type(element) != list or x.extend(element)]
(note that extend will flatten, while append will only add the nested list back to the end, unflattened).

Categories