Python: append/ extend method - python

Can someone explain me why after the for loop the list res is ['m']?
string = 'spam'
for x in string:
res =[]
res.extend(x)
print(res)
I expected the output to be res = ['s', 'p', 'a', 'm']

You are replacing the list object each step of your loop. The statement res = [] creates a new, empty list object, then adds a single letter to that list.
Without the loop, this is what you are doing:
>>> x = 's'
>>> res = []
>>> res.extend(x)
>>> res
['s']
>>> x = 'p'
>>> res = []
>>> res.extend(x)
['p']
>>> x = 'a'
>>> res = []
>>> res.extend(x)
>>> res
['a']
>>> res = []
>>> x = 'm'
>>> res.extend(x)
>>> res
['m']
Create the list outside of the loop, once:
string = 'spam'
res = []
for x in string:
res.extend(x)
print(res)
Now you don't keep replacing the list object with a new one each iteration of the for loop.
Again, removing the loop and doing the steps manually, now we have:
>>> res = []
>>> x = 's'
>>> res.extend(x)
>>> res
['s']
>>> x = 'p'
>>> res.extend(x)
>>> res
['s', 'p']
>>> x = 'a'
>>> res.extend(x)
>>> res
['s', 'p', 'a']
>>> x = 'm'
>>> res.extend(x)
>>> res
['s', 'p', 'a', 'm']
Not that you should be using res.extend() here; it only works because individual letters in string assigned to x are each also strings and even single-letter strings are still sequences. What you are really doing with res.extend(x) is the equivalent of for element in x: res.append(element), but x will always have just one element.
So this would work too:
string = 'spam'
res = []
for x in string:
res.append(x)
print(res)
or just extend res with the whole string value:
string = 'spam'
res = []
res.extend(string)
print(res)
or, if you just wanted a list of all the characters of a string, just use the list() function:
string = 'spam'
res = list(string)
print(res)
list() does exactly what you wanted to do with your loop: create an empty list, loop over the input, and add each element to the new list, which is then returned:
>>> string = 'spam'
>>> list(string)
['s', 'p', 'a', 'm']

You are resetting res every time inside the loop. You need to use this-
string = ‘spam’
res =[]
for x in string:
res.extend(x)
print(res)

You'll never get that output because for every iteration of the loop, you are setting res = [] and therefore only the last iteration will work by extending the blank list with 'm'.
The fixed code looks like this:
string = 'spam'
res = []
for x in string:
res.extend(x)
print(res)
Another note is that you probably should use .append in this case. .extend is for appending an entire iterable but since you are only adding one element at a time it isn't necessary. Check here for a good explanation.
Also a last note here is that you'll want to be careful with editing python code outside of plain text or code editors. You're using some leading and trailing apostrophes ‘’ instead of regular '' which will cause you trouble at some point.

You are always re-initializing the res list in the for-loop, that is why in the last iteration of the loop the list is initialized to [] an empty list and the last letter is added to it.
string = 'spam'
res =[]
for x in string:
res.extend(x)
print(res)
or to make it simple, use the list builtin which takes an iterable like a string and converts it into an list object:
>>> list('spam')
['s', 'p', 'a', 'm']

I think this is simplest way:
string = 'spam'
res = list(string)

Related

Python string to list per character

Good day I just want to understand the logic behind this code
lst = []
word = "ABCD"
lst[:0] = word
print(lst)
OUTPUT: ['A', 'B', 'C', 'D'] why not ['ABCD'] how?
for i in word: # this code I understand it's looping through the string
lst.append(i) # then appending to list
but the first code above I don't get the logic.
lst[:0] = ... is implemented by lst.__setitem__(slice(0, None, 0), ...), where ... is an arbitrary iterable.
The resulting slice is the empty list at the beginning of lst (though in this case, it doesn't really matter since lst is empty), so each element of ... is inserted into lst, starting at the beginning.
You can see this starting with a non-empty list.
>>> lst = [1,2,3]
>>> word = "ABCD"
>>> lst[:0] = word
>>> lst
['A', 'B', 'C', 'D', 1, 2, 3]
To get lst == ['ABCD'], you need to make the right-hand side an iterable containing the string:
lst[:0] = ('ABCD', ) # ['ABCD'] would also work.
Actually it's a well known way to convert string to a list character by character
you can find here -> https://www.geeksforgeeks.org/python-program-convert-string-list/
if you wanna try to get your list element like 'ABCD' then try
lst[:0] = [word,]
by doing that you specify that you need whole word as an element

How to delete repeat elements in this list?

I have a list is a = ['R','R','R','B','R','B','B','S','S']. my goal is to delete repeat 'R's and 'S's and then delete the 'B's (if there is only one R or S, just keep it). Therefore, I want the output to be ['R','R','S'], but mine is ['R', 'S'].
Can anyone help me take look my code? Thank you
This is my code
a = ['R','R','R','B','R','B','B','S','S'] # create a list to store R S B
a = [x for x in a if x != 'B'] # Delete all the B's
new_list = [] # create another list to store R and S without repeat
last = None
for x in a:
if last == x and (len(new_list) == 0 or new_list[-1] != x):
new_list.append(last)
last = x
print(new_list)
My output is this
['R', 'S']
but I want this
['R','R','S']
You could use itertools.groupby to group the elements first, then delete the B values:
from itertools import groupby
a = ['R','R','R','B','R','B','S','S'] # create a list to store R S B
[k for k, v in groupby(a) if k != 'B']
Result:
['R', 'R', 'S']
You could try this. This creates a new list without anything that is a repeat, and no 'B's.
a = ['R','R','R','B','R','B','B','S','S']
new_list = [] # create another list to store R and S without repeat
last = None
for x in a:
if last != x and x!='B':
new_list.append(x)
last = x
print(new_list)
Another option is to use a list comprehension:
a = ['R','R','R','B','R','B','B','S','S']
new_list = [ x for i,x in enumerate(a) if (a[i-1] != x and x!='B') or (i==0) ]
print(new_list)
Output from either example is the same:
['R', 'R', 'S']
Neither of these options require an import. However, I think the groupby code given by Mark Meyer is what I'd use in most cases.
You can use fromkeys in this case.
mylist = ["a", "b", "a", "c", "c"]
mylist = list(dict.fromkeys(mylist))
print(mylist) # ['a', 'b', 'c']

Adding each character in a line of input file to list, and adding each list to another list after each line

Basically what I am trying to do is read in each character from each line into a list, and after each line, add that list into another list (one list per line in input file, each list containing all the individual characters of each line)
This is what I have so far but it doesnt seem to be working and I can't figure out why.
allseq = []
with open("input.txt", "r") as ins:
seq = []
for line in ins:
for ch in line:
if ins != "\n":
seq.append(ch)
else:
allseq.append(seq)
seq[:] = []
print(allseq)
Strings in Python can be easily converted into literal lists of characters! Let's make a function.
def get_char_lists(file):
with open(file) as f:
return [list(line.strip()) for line in f.readlines()]
This opens a file for reading, reads all the lines, strips off extraneous whitespace, sticks a list of the characters into a list, and returns that last list.
Even though there is an easier way (#Pierce answer), there are two problems with your original code. The second is important to understand.
allseq = []
with open("input.txt", "r") as ins:
seq = []
for line in ins:
for ch in line:
if ch != "\n": # Use ch instead of ins here.
seq.append(ch)
else:
allseq.append(seq)
seq = [] # Don't clear the existing list, start a new one.
print(allseq)
Test file:
this is
some input
Output:
[['t', 'h', 'i', 's', ' ', 'i', 's'], ['s', 'o', 'm', 'e', ' ', 'i', 'n', 'p', 'u', 't']]
To clarify why the 2nd fix is needed, when you append an object to a list, a reference to the object is placed in the list. So if you later mutate that object the displayed content of the list changes, since it references the same object. seq[:] = [] mutates the original list to be empty.
>>> allseq = []
>>> seq = [1,2,3]
>>> allseq.append(seq)
>>> allseq # allseq contains seq
[[1, 2, 3]]
>>> seq[:] = [] # seq is mutated to be empty
>>> allseq # since allseq has a reference to seq, it changes too.
[[]]
>>> seq.append(1) # change seq again
>>> allseq # allseq's reference to seq displays the same thing.
[[1]]
>>> allseq.append(seq) # Add another reference to the same list
>>> allseq
[[1], [1]]
>>> seq[:]=[] # Clearing the list shows both references cleared.
>>> allseq
[[], []]
You can see that allseq contains the same references to seq with id():
>>> id(seq)
46805256
>>> id(allseq[0])
46805256
>>> id(allseq[1])
46805256
seq = [] Creates a new list with a different ID, instead of mutating the same list.
If you, or anyone else, prefer a one liner, here it is (based on Pierce Darragh's excellent answer):
allseq = [list(line.strip()) for line in open("input.txt").readlines()]

Anagram Function Returning None

I have to make a program that calls a function and searches for all the anagrams of the string from a file, returning a list of the words.
I made everything and it should work, but when I start it it gives me None. I even tried words that are in the file and it is the same.
def find_anagrams_in_wordlist(str, str_list):
str_list = get_dictionary_wordlist()
for int in range (0, len(str)):
anagram(str, str_list[int])
if anagram(str, str_list[int]):
return(str_list[int])
def find_anagrams(str):
str_list = get_dictionary_wordlist()
return find_anagrams_in_wordlist(str, str_list)
def test_find_anagrams():
print(find_anagrams("tenato"))
And this is my anagram() function:
def anagram(str1, str2):
str1_list = list(str1)
str1_list.sort()
str2_list = list(str2)
str2_list.sort()
return (str1_list == str2_list)
And this is my get_dictionary_wordlist() function:
def get_dictionary_wordlist():
text_file = open("dictionary.txt", "r")
return text_file.read().splitlines()
What should I change to make it work?
OK, first guess; this code:
def find_anagrams_in_wordlist(str, str_list):
str_list = get_dictionary_wordlist()
for int in range (0, len(str)):
anagram(str, str_list[int])
if anagram(str, str_list[int]):
return(str_list[int])
is working with range(0, len(str)) - the number of characters in 'tenato' - instead of range(0, len(str_list)) - the number of words in the dictionary.
This means you only test the first few dictionary words, and ignore the rest. Try it as:
def find_anagrams_in_wordlist(str, str_list):
str_list = get_dictionary_wordlist()
for word in str_list:
if anagram(str, word):
return word
(there's no need to count through lists in Python using range(), you can for item in mylist: directly).
NB. if this works, your design will still only return the first word which matches, not a list of words which match. You would need to build up a list of matches, and then return the list after the loop completes.
Lets examine what you have:
def find_anagrams_in_wordlist(str, str_list): # You shouldn't name something 'str' because it's a type.
str_list = get_dictionary_wordlist() # You are overwriting your incoming list with the same function call.
for int in range (0, len(str)): # You're executing your for loop once per letter in the candidate word.
anagram(str, str_list[int]) # This function executes but isn't doing anything
if anagram(str, str_list[int]):
return(str_list[int]) # If you find something you are exiting your for loop AND your function
def anagram(str1, str2):
str1_list = list(str1)
str1_list.sort() # The result of this is the same every time... and it's None
str2_list = list(str2)
str2_list.sort() # Always returns None
return (str1_list == str2_list) # This is the only real work being done here.
Finally, you are not actually accumulating your results:
def find_anagrams_in_wordlist(candidate, word_list): # Name your variables clearly
results = list() # For accumulating your results
sorted_candidate = sorted(candidate) # You only need to sort your candidate once
for word in word_list: # This is the cleanest way to loop through an iterable
sorted_word = sorted(word) # Sort the word once
if sorted_candidate == sorted_word: # Now check for equality: an additional function can obfuscate things
results.append(word) # If it's equal, add it to your results
return results # Send back your results
We can test it like so, in the REPL:
>>> lst = {"cat", "dog", "fish", "god"}
>>> find_anagrams_in_wordlist("odg", lst)
['god', 'dog']
>>> find_anagrams_in_wordlist("cat", lst)
['cat']
>>> find_anagrams_in_wordlist("shif", lst)
['fish']
>>> find_anagrams_in_wordlist("birds", lst)
[]
Note that in my solution I am using sorted not sort(). sort() won't accomplish the correct thing:
>>> x = "moonshot"
>>> y = list(x)
>>> y
['m', 'o', 'o', 'n', 's', 'h', 'o', 't']
>>> z = y.sort()
>>> z
>>> type(z)
<type 'NoneType'>
>>> sorted(x)
['h', 'm', 'n', 'o', 'o', 'o', 's', 't']

Not able to remove characters from a string in Python

I am trying to loop through a string x that represents the alphabet and at the same time compare those values with a list that contains some specific letters.
If there is a match in both the list and the string x, it should remove the specific character from the string x. It is a very simple and straightforward piece of code. I've followed the .replace method to the T. However, when I ran the code, the string x still shows up in its original state.
Here is my working code:
lettersGuessed = ['e', 'i', 'k', 'p', 'r', 's']
x = 'abcdefghijklmnopqrstuvwxyz'
for i in range(len(x)):
if x[i] in lettersGuessed:
x.replace(x[i],'')
print x "Available Letters"
Try the following
x = x.replace(x[i], '')
You're not reassigning the changed value back to the original string.
Simple mistake.
x = x.replace(x[i],'')
You can use join and a generator expression:
print("Available Letters","".join(ch if ch not in lettersGuessed else "" for ch in x ))
Using a loop, just iterate over the characters in lettersGuessed and update x each time:
for ch in lettersGuessed:
x = x.replace(ch,'') # assign the updated string to x
print("Available Letters",x)
Or iterating over x is the same logic:
for ch in x:
if ch in lettersGuessed:
x = x.replace(ch,'')
strings are immutable so you cannot change the string in place. You need to reassign x to the new string created with x.replace(ch,'')
In [1]: x = 'abcdefghijklmnopqrstuvwxyz'
In [2]: id(x)
Out[2]: 139933694754864
In [3]: id(x.replace("a","foo")) # creates a new object
Out[3]: 139933684264296
In [7]: x
Out[7]: 'abcdefghijklmnopqrstuvwxyz' # no change
In [8]: id(x)
Out[8]: 139933694754864 # still the same object
You could use python sets to achieve this :
a = ['a','b','d']
b = "abcdefgh"
print ''.join(sorted(list(set(b) - set(a))))
output:
cefgh Available letters
Or use list comprehensions to achieve this :
a = ['a','b','d']
b = "abcdefgh"
print ''.join([x for x in b if x not in a])

Categories

Resources