Difference between string.replace(c,'',1)) and string[1:] - python

So I am trying to trace a recursive function and I'm having difficulties tracing this:
I'm trying to trace a code on permutations but this confuses me:
# doesn't work
def permutations(string):
if len(string) == 1:
return string
recursive_perms = []
for c in string:
for perm in permutations(string[1:]):
recursive_perms.append(c+perm)
return set(recursive_perms)
# works
def permutations(string):
if len(string) == 1:
return string
recursive_perms = []
for c in string:
for perm in permutations(string.replace(c,'',1)):
recursive_perms.append(c+perm)
return set(recursive_perms)
I'm horrible at tracing recursion currently, and I don't know the difference between the first and second function but the 2nd one works first one doesn't. The difference is the replace. Whats the different between the replace and doing string[1:]? Is there anyway you could change the replace into string slicing?

str.replace(old, new[, count]) replaces old with new, optionally only for the first count instances
str[1:] returns a slice of str from the character at the second index until the last index, effectively returning the entire string except for it's first character.
What really happens when you call str[1:] is that you're calling str.__getitem__(slice(1, None))

Related

Why the output is two string when I pass a one character string to a python function

I've created a function called swap for an experiment. The function is as below:
def swap(x):
return x[-1:] + x[1:-1] + x[0:1]
When I try to pass a string "a", the output is "aa". I am not sure how's that happen. Thanks in advance if someone knows the reason.
Your function returns a new string based on:
The last letter of your string (a)
everything after the first letter but before the last letter (empty in your case)
and the first letter of your string (a)
So because your last letter is your first letter, you get them twice.
To swap them correctly, you'll have to test for string length:
def swap(x):
if len(x) < 2:
return x
return x[-1] + x[1:-1] + x[0]
Now that you know that in the last line x is at least two characters long, you also don't need slicing for the first/last character and can use direct element access (x[0]/x[-1]).
Actually this is ok.
x[-1:] will return the last character, becuase -1 starts from the end
x[0:1] will return the first character from beginning
x[1:-1] is nothing in this case because you don't have the second character
Btw for swap use return x.reverse() or return x[::-1]

Is there a way to select a group of indexes and remove them?

I am making a decode method, which selects a set of index values within strings to remove. But right now the problem is i am unable to understand how to select a set of indices to remove
I have tried making a list of items to designate and remove if found in the string, but this would only work for only a few types of string sets.
def decode(string, n):
for i in range(0,len(string), n):
string = string.replace(string[i],'')
return string
here n is the number of values to remove at a given index as well as the index from where to start removing the said values
I understand how to step through an index, but I am not sure how to remove string values according to the index.
print(decode('#P#y#t#h#o#n#',1)) #this works out to be Python
print(decode('AxYLet1x3’s T74codaa7e!',3 )) #this does not, this is supposed to be 'Let's Code'
With "switcher" flag:
def decode(inp_str, n):
s = ''
flag = True
for i in range(0, len(inp_str), n):
flag = not flag
if flag: s += inp_str[i: i + n]
return s
print(decode('#P#y#t#h#o#n#', 1)) # Python
print(decode('AxYLet1x3’s T74codaa7e!', 3)) # Let’s code!
Different approach would be to pick the characters at the right positions:
def decode(string, n):
res = ''
for i in range(len(string)//(2*n)+1):
res += string[2*n*i+n:2*n*i+2*n]
return res
Don't change the size of an iterable when going through it!
The best would be to replace the character with some placeholder that can't be in the string, and then stripping it.
E.g. for your first example you already have that string format. Removing them outside the loop (remember, loop is for marking the characters for deletion) would be:
return ''.join(c for c in string if c!='#')
As for the loop itself in this approach, I'll leave it up to you to debug it now. ;) See how index moves in the loop, see what your replace in fact does! E.g. as I said in the comment, n=1 would go through literally every character, not every second character!
Another solution is smart slicing with indexes. Assuming from your examples that you want to 'remove n, keep n' code:
def decode(string, n):
result = ""
for i in range(n,len(string), 2*n): # first index we want to keep is n, next is 3n, 5n... so we're jumping by 2n each time
result += string[i: i+n]
return result
First, you're returning right after the first iteration. Second, you're only replacing character at n'th position with "".
This should do what you require, it'll replace every 'n' number of characters after every 'n' index:
def decode(string, n):
for i in range(0,len(string)-1,n):
string = string[:i] + string[i+n:] # Remove elements at index "i", till "i+n"
return string
Output:
print(decode('#P#y#t#h#o#n#',1)) # Output = Python
print(decode('AxYLet1x3’s T74codaa7e!',3 )) # Output = Let's Code

Python: Assertion error when converting a string to binary

I am getting AssertionError when testing some basic functions in my python program. This is the scenario:
I have written a function that converts a single letter into binary from ASCII:
def ascii8Bin(letter):
conv = ord(letter)
return '{0:08b}'.format(conv)
Next there's a function that uses the previous function to convert all the letters in a word/sentence into binary:
def transferBin(string):
l = list(string)
for c in l:
print ascii8Bin(c)
Now when I try to assert this function like this:
def test():
assert transferBin('w') == '01110111'
print "You test yielded no errors"
print test()
It throws an AssertionError. Now I looked up the binary alphabet and tripple checked: w in binary is definitely 01110111. I tried calling just the transferBin('w') and it yielded 01110111 like it should.
I am genuinely interested in why the assertion fails. Any insight is very much appreciated.
Your function doesn't return anything. You use print, which writes text to stdout, but you are not testing for that.
As such, transferBin() returns None, the default return value for functions without an explicit return statement.
You'll have to collect the results of each ascii8Bin() result into a list and join the results into a string:
def transferBin(string):
results = [ascii8Bin(c) for c in l]
return '\n'.join(results)
This'll use newlines to separate the result for each character; for your single character 'w' string that'll give you the expected string.
Note that you don't need to turn l in to a list; you can iterate over strings directly; you'll get individual characters either way.
You need to return, you are comparing to None not the string. python will return None from a function if you don't specify a return value.
def transferBin(s):
l = list(s)
for c in l:
return ascii8Bin(c) # return
You are basically doing assert None == '01110111', also if you are only going to have single character string simply return ascii8Bin(string), having a loop with a return like in your code will return after the first iteration so the loop is redundant.
If you actually have multiple characters just use join and just iterate over the string you don't need to call list on it to iterate over a string:
def transferBin(s):
return "".join(ascii8Bin(ch) for ch in s)
You can also just do it all in your transferBin function:
def transferBin(s):
return "".join('{0:08b}'.format(ord(ch)) for ch in s)

Explanation for reverse_string recursive function

No matter how many times I run it by Python visualizer, I can't figure out how this code works; can someone PLEASE tell me how the recursion of this following code works?
def reverse_strings(string):
if len(string) == 0: return ''
else: return reverse_strings(string[1:]) + string[0]
reverse_strings('hello')
I wrote it myself, and it works, but I have no idea how it works. I know return recursion works by running the "ello" into the recursive function, but I can't for the life of me understand how it's printing things backwards.
The concept of recursion is that you call a the same function until the base case is encountered. In your case, the base case is when len(string) == 0, where you return an empty string to the caller, which was a previous version of the same function reverse_strings, but with different parameters (usually a more "complex" function).
Suppose you have this simple string hi, your function would behave like this:
Check if the base case is reached, if yes, return an empty string, otherwise go to next statement. Since we don't have an empty string, we go to the next statement.
Next statement calls the same function reverse_strings, but with different parameters than when you call it the first time to run it; in fact, the first time you call it, you do something like this reverse_strings('hi'). In the else, you are calling the function with a smaller version of your string hi, observe in the following statement: return reverse_strings(string[1:]) + string[0] that string[1:] is just i. Now, basically you have return reverse_strings('i') + string[0]. Note that string[0] is H. Here, reverse_strings('i'), as I said above, you are calling your function again, but with a smaller version of your string i.
Now, we are inside another function call. The first statement if len(string) == 0: return '' is evaluated. Is it true? No, because len(string) is still different from 0. So we pass to the next statement else: return reverse_strings(string[1:]) + string[0]. Now, note that we are going to call the same function again. but with a smaller string, in this case, an empty string, since string[1:] of i is an empty string. So our call can be summarised like this return reverse_strings('') + i.
We are now in another "simplified version" of reverse_strings. The first statement is evaluated if len(string) == 0: return ''. Is it true? Yes, because, remember, our string is now an empty string. What happens now is that you return an empty string to the caller, which is the function in the point 3.
Now, we have just returned an empty string to the caller at point 3, so we have return '' + i. '' + i is nothing else than simply i, which you are going to return to the caller of this function at pointer 3, which is the function at point 2.
Now, you have just returned i to the caller, specifically you have just returned i to this statement return reverse_strings('i') + string[0], where string[0] is H and reverse_strings('i') is just i that you have just returned. So, now you have iH, and you have just reversed the string.
It uses slicing to concatenate the first letter onto the end, then pass the 2nd to remaining letters into the recursive function again.
string[1:] on the first call is ello string[0] is h:
2nd recursive call string[1:] -> llo string[0] -> e
3rd string[1:] ->lo string[0] -> l
4th string[1:] ->o string[0] -> l
5th string[1:] ->"" string[0] -> o
So reverse_strings(string[1:]) calls the function recursively moving across the string and string[0] concatenates each letter starting from the end which is what is returned at the end.
The graph below may help:
To really understand this, I would express it in a declarative, sort-of logical form.
Here's your code:
1: if len(string) == 0: return ''
2: else: return reverse_strings(string[1:]) + string[0]
I'll call the first element of a string (string[0]) its head and the remainder (string[1:]) its tail. If a string is only 1 character long, we consider its tail to be the empty string. In terms of that vocabulary, here are the rules for what it means to reverse a string:
The empty string reversed is the empty string.
Any other string reversed is the reversed version of its tail, followed by its head.
In the case of, for example, abcd, we apply rule 2 since rule 1 doesn't apply:
abcd reversed is bcd reversed, followed by a.
Ok, what's bcd reversed? Well, we can apply the same rule:
bcd reversed is cd reversed, followed by b.
and down the chain:
cd reversed is d reversed, followed by c,
d reversed is '' reversed, followed by d,
'' reversed is '', by rule 1, because it is the empty string.
Going back up this list, you get:
'' followed by d followed by c followed by b followed by a
which is dcba, which is what we wanted!
Wrapping your head around recursion isn't easy. Try to solve some other problems with it or do some exercises that require it; this kind of practice really helps understanding.

Swapping every second character in a string in Python

I have the following problem: I would like to write a function in Python which, given a string, returns a string where every group of two characters is swapped.
For example given "ABCDEF" it returns "BADCFE".
The length of the string would be guaranteed to be an even number.
Can you help me how to do it in Python?
To add another option:
>>> s = 'abcdefghijkl'
>>> ''.join([c[1] + c[0] for c in zip(s[::2], s[1::2])])
'badcfehgjilk'
import re
print re.sub(r'(.)(.)', r'\2\1', "ABCDEF")
from itertools import chain, izip_longest
''.join(chain.from_iterable(izip_longest(s[1::2], s[::2], fillvalue = '')))
You can also use islices instead of regular slices if you have very large strings or just want to avoid the copying.
Works for odd length strings even though that's not a requirement of the question.
While the above solutions do work, there is a very simple solution shall we say in "layman's" terms. Someone still learning python and string's can use the other answers but they don't really understand how they work or what each part of the code is doing without a full explanation by the poster as opposed to "this works". The following executes the swapping of every second character in a string and is easy for beginners to understand how it works.
It is simply iterating through the string (any length) by two's (starting from 0 and finding every second character) and then creating a new string (swapped_pair) by adding the current index + 1 (second character) and then the actual index (first character), e.g., index 1 is put at index 0 and then index 0 is put at index 1 and this repeats through iteration of string.
Also added code to ensure string is of even length as it only works for even length.
string = "abcdefghijklmnopqrstuvwxyz123"
# use this prior to below iteration if string needs to be even but is possibly odd
if len(string) % 2 != 0:
string = string[:-1]
# iteration to swap every second character in string
swapped_pair = ""
for i in range(0, len(string), 2):
swapped_pair += (string[i + 1] + string[i])
# use this after above iteration for any even or odd length of strings
if len(swapped_pair) % 2 != 0:
swapped_adj += swapped_pair[-1]
print(swapped_pair)
badcfehgjilknmporqtsvuxwzy21 # output if the "needs to be even" code used
badcfehgjilknmporqtsvuxwzy213 # output if the "even or odd" code used
Here's a nifty solution:
def swapem (s):
if len(s) < 2: return s
return "%s%s%s"%(s[1], s[0], swapem (s[2:]))
for str in ("", "a", "ab", "abcdefgh", "abcdefghi"):
print "[%s] -> [%s]"%(str, swapem (str))
though possibly not suitable for large strings :-)
Output is:
[] -> []
[a] -> [a]
[ab] -> [ba]
[abcdefgh] -> [badcfehg]
[abcdefghi] -> [badcfehgi]
If you prefer one-liners:
''.join(reduce(lambda x,y: x+y,[[s[1+(x<<1)],s[x<<1]] for x in range(0,len(s)>>1)]))
Here's a another simple solution:
"".join([(s[i:i+2])[::-1]for i in range(0,len(s),2)])

Categories

Resources