Editing elements in a list in python - python

How do I remove a character from an element in a list?
Example:
mylist = ['12:01', '12:02']
I want to remove the colon from the time stamps in a file, so I can more easily convert them to a 24hour time. Right now I am trying to loop over the elements in the list and search for the one's containing a colon and doing a substitute.
for num in mylist:
re.sub(':', '', num)
But that doesn't seem to work.
Help!

The list comprehension solution is the most Pythonic one, but, there's an important twist:
mylist[:] = [s.replace(':', '') for s in mylist]
If you assign to mylist, the barename, as in the other answer, rather than to mylist[:], the "whole-list slice", as I recommend, you're really doing something very different than "replacing entries in the list": you're making a new list and just rebinding the barename that you were previously using to refer to the old list.
If that old list is being referred to by multiple names (including entries in containers), this rebinding doesn't affect any of those: for example, if you have a function which takes mylist as an argument, the barename assignment has any effect only locally to the function, and doesn't alter what the caller sees as the list's contents.
Assigning to the whole-list slice, mylist[:] = ..., alters the list object rather than mucking around with switching barenames' bindings -- now that list is truly altered and, no matter how it's referred to, the new value is what's seen. For example, if you have a function which takes mylist as an argument, the whole-list slice assignment alters what the caller sees as the list's contents.
The key thing is knowing exactly what effect you're after -- most commonly you'll want to alter the list object, so, if one has to guess, whole-list slice assignment is usually the best guess to take;-). Performance-wise, it makes no difference either way (except that the barename assignment, if it keeps both old and new list objects around, will take up more memory for whatever lapse of time both objects are still around, of course).

Use a list comprehension to generate a new list:
>>> mylist = ['12:01', '12:02']
>>> mylist = [s.replace(':', '') for s in mylist]
>>> print mylist
['1201', '1202']
The reason that your solution doesn't work is that re.sub returns a new string -- strings are immutable in Python, so re.sub can't modify your existing strings.

for i, num in enumerate(mylist):
mylist[i] = num.replace(':','')

You have to insert the return of re.sub back in the list. Below is for a new list. But you can do that for mylist as well.
mylist = ['12:01', '12:02']
tolist = []
for num in mylist:
a = re.sub(':', '', num)
tolist.append(a)
print tolist

Strings in python are immutable, meaning no function can change the contents of an existing string, only provide a new string. Here's why.
See here for a discussion on string types that can be changed. In practice though, it's better to adjust to the immutability of strings.

Instead of list comprehension, you can also use a map call:
mylist = ['12:01', '12:02']
map(lambda f: f.replace(':', ''), mylist)
Returns:
['1201', '1202']

Related

Replace function in list of strings

I would like to iterate through a list of strings and replace each instance of a character ('1', for example) with a word. I am confused why this would not work.
for x in list_of_strings:
x.replace('1', 'Ace')
Side note, the strings within the lists are multiple characters long. ('1 of Spades)
You can use a list comprehension:
list_of_strings = [x.replace('1', 'Ace') for x in list_of_strings]
This is natural in Python. There is no significant benefit in changing your original list directly; both methods will have O(n) time complexity.
The reason your code does not work is str.replace does not work in place. It returns a copy, as mentioned in the docs. You can iterate over a range object to modify your list:
for i in range(len(list_of_strings)):
list_of_strings[i] = list_of_strings[i].replace('1', 'Ace')
Or use enumerate:
for idx, value in enumerate(list_of_strings):
list_of_strings[idx] = value.replace('1', 'Ace')

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.

Python: User input as a list index

I am trying to use user input as an index for a list, but I keep getting the error "TypeError: list indices must be integers, not tuple." Here is what I have:
def sort(j, k):
sublist = list[j, k]
print sublist
sorted = sublist.sort
print sorted
operation = raw_input()
sort(operation[5], operation[7])
The user is supposed to input
SORT 3 5
and a subset of the original list will be sorted.
Your (immediate) problem is at this line:
sublist = list[j, k]
Presumably list is a list of items1. When you do somelist[a, b], python sees something equivalent to somelist[(a, b)]. So, you can see, you're indexing somelist with a tuple (which doesn't work). Chances are that you want a slice. In that case, you'll do:
sublist = list[j:k]
Even after making this change however, you'll still have problems -- Notably, j and k in your code are of type str and lists want to be indexed/sliced with integers (or None...)2. So, now we have:
sublist = list[int(j):int(k)]
At this point, you might stop seeing errors, but you won't see the results you want which brings us to the next problem.
sorted = sublist.sort
Here you're just assigning a bound method to a name. You're not actually sorting anything. If you want to sort the sublist (in place), you'd do:
sublist.sort()
print(sublist)
If you are ok with sorting it out of place, you can use the builtin sorted function (provided you haven't named something else sorted ;-)
print(sorted(sublist))
1Note, it is generally accepted that naming a variable the same thing as a builtin type can lead to hard to read and debug code :-).
2While we're at it, I might mention there is a better way to chunk up your string -- You can .split it. e.g. operation.split() will give you ['SORT', '5', '7'] rather than needing to make assumptions about the input and indexing the input string.
You have a few problems here:
Your function is called sort, which is the name of a built-in method.
You are not calling the method in this line sorted = sublist.sort (its missing ()).
You are giving each letter from the input as an argument to your function.
This: list[j,k] is what is causing your problem, because j,k is a tuple.
sort is in an in-place operation, so it will return None, which is what you will end up printing.
To fix these issues:
def my_sorter(j, k): # Changed method name
sublist = my_list[int(j):int(k)] # You need j:k
sublist.sort() # Note, no return value, because its in-place
print sublist
user_input = raw_input('Please enter the indices: ')
j,k = user_input.split()
my_sorter(j,k)

Deleting Numbers From A String -Python

I am creating a program for a high school course and our teacher is very specific about what is allowed into our programs. We use python 2.x and he only allows if statements, while loops, functions, boolean values, and lists. I am working on a project that will print the reversal of a string, then print again the same reversal without the numbers in it but I cannot figure it out. Help please. What i have so far is this..
def reverse_str(string):
revstring =('')
length=len(string)
i = length - 1
while i>=0:
revstring = revstring + string[i]
i = i - 1
return revstring
def strip_digits(string):
l = [0,1,2,3,4,5,6,7,8,9]
del (l) rev_string
string = raw_input("Enter a string->")
new_str = rev_str(string)
print new_str
I cannot figure out how to use the "del" function properly, how do i delete any of the items in the list from the reversed string..thanks
In general, you have two options for a task like this:
Iterate through the items in your list, deleting the ones that you do not want to keep.
Iterate through the items in your list, copying the ones that you do want to keep to a new list. Return the new list.
Now, although I would normally prefer option (2), that won't help with your specific question about del. To delete an item at index x from a list a, the following syntax will do it:
del a[x]
That will shift all the elements past index x to the left to close the gap left by deleting the element. You will have to take this shift into account if you're iterating through all the items in the list.
Type str in python is immutable (cannot be altered in place) and does not support the del item deletion function.
Map the characters of the string to a list and delete the elements you want and reconstruct the string.
OR
Iterate through the string elements whilst building a new one, omitting numbers.
correct usage of del is:
>>> a = [1, 2, 3]
>>> del a[1]
>>> a
[1, 3]
You could iterate back over the string copying it again but not copying the digits... It would be interesting for you to also figure out the pythonic way to do everything your not allowed to. Both methods are good to know.

Python: create a list containing dicts

how would you turn this string:
str='ldap:alberthwang,eeid:67739|ldap:meng,eeid:107,building:CL5'
into a list that give you this:
print x[1]['building']=CL5
which would be:
x=[{'ldap':'alberthwang','eeid':'67739'},{'ldap':'meng','eeid':'107','building':'CL5'}]
i've tried to split the string first and append to a list:
sample=[]
for s in str.split('|'):
sample.append(s)
But i'm stuck on how to turn the list items into a dictionary that i can then use to populate another list.
text='ldap:alberthwang,eeid:67739|ldap:meng,eeid:107,building:CL5'
sample=[
dict(item.split(':') for item in part.split(','))
for part in text.split('|')]
print(sample)
# [{'eeid': '67739', 'ldap': 'alberthwang'}, {'building': 'CL5', 'eeid': '107', 'ldap': 'meng'}]
print(sample[1]['building'])
# CL5
List comprehensions are a very convenient way to construct
lists such as this.
A dict can be constructed from an iterable of key-value pairs. The iterable used above was a generator expression.
str is a built-in type, so assigning a string to str overwrites
the builtin. It's better to choose some other variable name to avoid
future surprising bugs.
I read and write list comprehensions backwards:
[ expression # (3)
for variable in # (2)
iterable # (1)
]
(1): First, understand the iterable. In the solution above, this is text.split('|').
(2): for variable in causes variable to be assigned to the values in iterable, one at a time.
(3): Finally, expression can be any Python expression, (usually) using variable.
The syntax for generator expressions is almost the same. The difference between a list comprehension and a generator expression is that a list comprehension returns a list, while a generator expression returns an iterator -- an object that yields its contents on-demand (as it is looped over, or when next is called) instead of generating all the items at once as is the case with lists.
A list can consume a lot of memory if the list is long.
A generator expression will consume less memory (and can even be infinite) because not all elements have to exist in memory at the same time.
Using str as a variable name is a bad idea, since it overshadows the built-in str.
s ='ldap:alberthwang,eeid:67739|ldap:meng,eeid:107,building:CL5'
res = [dict(colonStr.split(':') for colonStr in ds.split(','))
for ds in s.split('|')]
stores the result you what in res.
The key insight here is that dict can take a list of key/value pairs. So, you can do this using a comprehension like this:
string = 'ldap:alberthwang,eeid:67739|ldap:meng,eeid:107,building:CL5'
list_of_dicts = [dict(item.split(':') for item in items.split(',')) for items in string.split('|')]
print list_of_dicts
Maybe this way:
>>> s = 'ldap:alberthwang,eeid:67739|ldap:meng,eeid:107,building:CL5'
>>> x = [dict([d.split(':') for d in ls.split(',')]) for ls in s.split('|')]
>>> x[1]['building']
>>> 'CL5'

Categories

Resources