Using range function in Python - python

I am new to learning Python and have a question about using the range function to iterate a string.
Let's say I need to capitalize everything in the following string:
string = 'a b c d e f g'
Can I just write the following code?
for i in string:
i = i.upper()
return string
Or should I use the range function to iterate every element in the string?
Finally, a more general question is whenever I need to iterate all elements in a string/list, when should I use the range function and when can I just use the "for" loop?

Strings are a bad example, because strings in Python cannot be changed. You have to build a new one:
new = ''
for i in string:
new += i.upper()
For the sake of example, we're all going to ignore the fact that new = string.upper() would do this in one statement.
In general, when you iterate through an object, you are handed references to the members. You can't change the container object, but if the inner object is mutable, you can change it. Consider this silly example:
a = [[1],[2],[3],[4]]
for element in a:
element[0] *= 2
This will result in a being [[2],[4],[6],[8]], because we are allowed to modify those inner lists. We can't change the outer list.
AS A GENERAL RULE, if you find yourself writing for i in range(len(xxx)):, then there is a better way to do it. It isn't ALWAYS true, but it's a key Python learning point.

Related

Why do sequence for loops don't seem to work well in Python?

I'm trying to convert every string in a list to it's lowercase format using this function:
def lower_list(strings):
for string in strings:
string = string.lower()
return strings
But this implementation is not working, however when using the range funtion and I iterate using an index:
def lower_list(strings):
for i in range(len(strings)):
strings[i] = strings[i].lower()
return strings
I do get every element on my list converted to lowercase:
> print(lower_list(mylist))
['oh brother where art thou', 'hello dolly', 'monsters inc', 'fargo']
But with the first implementation I get the original list with Uppercase values, am I missing something important in how the for loop works?
In the first case, all you are doing is storing the lowercase value in a variable, but the list is untouched.
In the second case, you are actually updating the value in the list at that index.
You can also use a lambda function here:
def lower_list(strings):
return list(map(lambda x: x.replace(x, x.lower()), strings))
List comprehension is the easiest and the best:
def lower_list(strings):
return [string.lower() for string in strings]
The reason the first one does not work is that it is not actually modifying the value inside of the list, rather it is just affecting a copy of the value in the list. When you use the index-based function, it modifies the list itself.
def lower_list(strings):
for string in strings:
index_of_string = strings.index(string)
string = string.lower()
strings[index_of_string] = string
return strings
If you want the first one to work, maybe you can try something like that, but thats a bad way of doing it, just showing it as an example so maybe you'll understand better. You need the index of that string so you can replace it in the list. In your first attempt, you do not replace anything in the list.

Creating multiple lists within a dictionary using an iteration

I am currently writing a small bit of logic for my HTML page. My aim is to create variables (lists) within an iteration (using the iteration to create the names of said lists as the amount of them will be unknown to the program). I am currently creating the lists like this:
maps={}
currentMap = elements[0].process
counter=0
for i in elements:
if(counter==0):
maps["mapsEle{0}".format(counter)]=[]
counter+=1
if(i.process!=currentMap):
currentMap = i.process
maps["mapEle{0}".format(counter)]=[]
counter+=1
else:
print("No change found, keeping heading the same.")
However as you can probably tell, this does not create a list but a string. I try to print the variables (e.g. mapsEle0) and it returns the variable name (e.g. print(mapsEle0) returns "mapsEle0") this too me is suprising as I would have thought if the dictionary is saving it as a string it would print "[]".
So I am looking for a way to create lists within the dictionary in that iteration I am using there, basically want to just reformat my declaration. Cheers in advance everyone :)
Edit:
As requested here is the code where I attempt to append. Please note I want to append 'i' into the lists and no the dictionary.
for i in maps:
for x in elements:
if(x.process!=currentMap):
currentMap=x.process
elif(x.process==currentMap):
#i.append(x)
The syntax of your print statement is wrong, if you want to access the contents of the dictionary, you need to use different notation.
Instead of print('mapsEle0') you need to do print(maps['mapsEle0']).
Update:
Unfortunately your description of what you want and your code are a bit conflicting, so if you can, please try to explain some more what this code is supposed to do.
for i in maps.iterkeys():
for x in elements:
if(x.process!=currentMap):
currentMap=x.process
elif(x.process==currentMap):
maps[i].append(x)
This will iterate over all keys of maps ('mapsEle0'...'mapsEleN') and add x to the contained list if the elif condition is fulfilled.
You're printing the string by doing print('mapsEle0').
To print the dict, you must print(maps) - 'll print the whole dictionary, OR, to print a specific key/element print(maps['mapsEle0'])
To elaborate it further here's a interpreter session:
>>> maps = {}
>>> counter = 0
>>> maps["mapsEle{0}".format(counter)]=[]
>>> maps
{'mapsEle0': []}
>>>
>>> print(maps)
{'mapsEle0': []}
>>>
>>> print(maps['mapsEle0'])
[]
>>>
For the append part:
>>> maps['mapsEle1'].append('hello')
>>> print(maps['mapsEle1'])
['hello']
Edit 2: Your statement is still not clear
As requested here is the code where I attempt to append. Please note I
want to append 'i' into the lists and no the dictionary.
I think sobek has got it right - you want to append x to the mapsEle0, mapsEle1 lists, which are keys in maps dictionary.
for i in maps.iterkeys():
for x in elements:
if(x.process!=currentMap):
currentMap=x.process
elif(x.process==currentMap):
maps[i].append(x)

Python Replace Character In List

I have a Python list that looks like the below:
list = ['|wwwwwwwwadawwwwwwwwi', '|oooooooocFcooooooooi']
I access the letter in the index I want by doing this:
list[y][x]
For example, list[1][10] returns F.
I would like to replace F with a value. Thus changing the string in the list.
I have tried list[y][x] = 'o' but it throws the error:
self.map[y][x] = 'o'
TypeError: 'str' object does not support item assignment
Can anybody help me out? Thanks.
As #Marcin says, Python strings are immutable. If you have a specific character/substring you want to replace, there is string.replace. You can also use lists of characters instead of strings, as described here if you want to support the functionality of changing one particular character.
If you want something like string.replace, but for an index rather than a substring, you can do something like:
def replaceOneCharInString(string, index, newString):
return string[:index] + newString + string[index+len(newString):]
You would need to do some length checking, though.
Edit: forgot string before the brackets on string[index+len(newString):]. Woops.
Since python strings are immutable, they cannot be modified. You need to make new ones. One way is as follows:
tmp_list = list(a_list[1])
tmp_list[10] = 'o' # simulates: list[1][10]='o'
new_str = ''.join(tmp_list)
#Gives |oooooooococooooooooi
# substitute the string in your list
a_list[1] = new_str
As marcin says, strings are immutable in Python so you can not assign to individual characters in an existing string. The reason you can index them is that thay are sequences. Thus
for c in "ABCDEF":
print(c)
Will work, and print each character of the string on a separate line.
To achieve what you want you need to build a new string.For example, here is a brute force approach to replacing a single character of a string
def replace_1(s, index, c)
return s[:index] + c + s[index+1:]
Which you can use thus:
self.map[y] = replace_1(self.map[y], x, 'o')
This will work because self.map is list, which is mutable by design.
Let use L to represent the "list" since list is a function in python
L= ['|wwwwwwwwadawwwwwwwwi', '|oooooooocFcooooooooi']
L[1]='|oooooooococooooooooi'
print(L)
Unfortunately changing a character from an object (in this case) is not supported. The proper way would be to remove the object and add a new string object.
Output
['|wwwwwwwwadawwwwwwwwi', '|oooooooococooooooooi']

What's this syntax in python mean?

I have the following code in python:
a = "xxx" # a is a string
b = "yyy" # b is another string
for s in a, b:
t = s[:]
...
I dont understand the meaning of for line. I know a, b returns a tuple. But what about looping through a, b? And why you need t = s[:]. I know s[:] creates a copy of list. But if s is a string, why don't you write t = s to make a copy of the string s into t?
Thank you.
The meaning of the for loop is to iterate over the tuple (a, b). So the loop body will run twice, once with s equal to a and again equal to b.
t = s[:]
On the face of it, this creates a copy of the string s, and makes t a reference to that new string.
However strings are immutable, so for most purposes the original is as good as a copy. As an optimization, Python implementations are allowed to just re-use the original string. So the line is likely to be equivalent to:
t = s
That is to say, it will not make a copy. It will just make t refer to the same object s refers to.

Python: removing specific lines from an object

I have a bit of a weird question here.
I am using iperf to test performance between a device and a server. I get the results of this test over SSH, which I then want to parse into values using a parser that has already been made. However, there are several lines at the top of the results (which I read into an object of lines) that I don't want to go into the parser. I know exactly how many lines I need to remove from the top each time though. Is there any way to drop specific entries out of a list? Something like this in psuedo-python
print list
["line1","line2","line3","line4"]
list = list.drop([0 - 1])
print list
["line3","line4"]
If anyone knows anything I could use I would really appreciate you helping me out. The only thing I can think of is writing a loop to iterate through and make a new list only putting in what I need. Anyway, thanlks!
Michael
Slices:
l = ["line1","line2","line3","line4"]
print l[2:] # print from 2nd element (including) onwards
["line3","line4"]
Slices syntax is [from(included):to(excluded):step]. Each part is optional. So you can write [:] to get the whole list (or any iterable for that matter -- string and tuple as an example from the built-ins). You can also use negative indexes, so [:-2] means from beginning to the second last element. You can also step backwards, [::-1] means get all, but in reversed order.
Also, don't use list as a variable name. It overrides the built-in list class.
This is what the slice operator is for:
>>> before = [1,2,3,4]
>>> after = before[2:]
>>> print after
[3, 4]
In this instance, before[2:] says 'give me the elements of the list before, starting at element 2 and all the way until the end.'
(also -- don't use reserved words like list or dict as variable names -- doing that can lead to confusing bugs)
You can use slices for that:
>>> l = ["line1","line2","line3","line4"] # don't use "list" as variable name, it's a built-in.
>>> print l[2:] # to discard items up to some point, specify a starting index and no stop point.
['line3', 'line4']
>>> print l[:1] + l[3:] # to drop items "in the middle", join two slices.
['line1', 'line4']
why not use a basic list slice? something like:
list = list[3:] #everything from the 3 position to the end
You want del for that
del list[:2]
You can use "del" statment to remove specific entries :
del(list[0]) # remove entry 0
del(list[0:2]) # remove entries 0 and 1

Categories