If I try the following snippets of code on a binary tree, and try to print the arr and string later, arr gives me the correct result but string is empty. Any thoughts? Is it something to do with lists being passed by reference and strings passed by value?
def post_order(root, arr = []):
if(root is not None):
post_order(root.left, arr)
post_order(root.right, arr)
arr.append(root.value)
def post_order1(root, string = ''):
if(root is not None):
post_order1(root.left, string)
post_order1(root.right, string)
string += str(root.value)
# assume I've made my binary tree
arr, string = [], ''
post_order(root, arr)
post_order1(root, string)
print arr, string
# arr holds the correct post-order sequence
# string is empty
In Python, lists are mutable and strings are immutable. This means that a list can be modified, but a string cannot. Strings can only be reassigned.
In your function, you are modifying the list using .append(), but you are only reassigning your string +=
Arr is an array, which you extend. String passed to post_order1 is an immutable object and a copy is created when updated. As a result, the original string stays unchanged.
You should rectify your code like this:
def post_order1(root, string = ''):
if not root : return string
left = post_order1(root.left, string)
right = post_order1(root.right, left)
return right + str(root.value)
Related
I'm trying to write a function to return the longest common prefix from a series of strings. Using a debugger, saw that my function reaches the longest common prefix correctly, but then when it reaches the statement to return, it begins reverting to earlier stages of the algorithm.
For test case strs = ["flower","flow","flight"]
The output variable holds the following values:-
f > fl > f
instead of returning fl.
Any help would be appreciated, because I don't really know how to Google for this one. Thank you.
class Solution(object):
def longestCommonPrefix(self, strs, output = ''):
#return true if all chars in string are the same
def same(s):
return s == len(s) * s[0]
#return new list of strings with first char removed from each string
def slicer(list_, list_2 = []):
for string in list_:
string1 = string[1:]
list_2.append(string1)
return list_2
#return string containing first char from each string
def puller(list_):
s = ''
for string in list_:
s += string[0]
return s
#pull first character from each string
s = puller(strs)
#if they are the same
#add one char to output
#run again on sliced list
if same(s):
output += s[0]
self.longestCommonPrefix(slicer(strs), output)
return output
This can be handled with os.path.commonprefix.
>>> import os
>>> strs = ["flower","flow","flight"]
>>> os.path.commonprefix(strs)
'fl'
It doesn't "revert". longestCommonPrefix potentially calls itself - what you're seeing is simply the call-stack unwinding, and flow of execution is returning to the calling code (the line that invoked the call to longestCommonPrefix from which you are returning).
That being said, there's really no need to implement a recursive solution in the first place. I would suggest something like:
def get_common_prefix(strings):
def get_next_prefix_char():
for chars in zip(*strings):
if len(set(chars)) != 1:
break
yield chars[0]
return "".join(get_next_prefix_char())
print(get_common_prefix(["hello", "hey"]))
You are looking at the behavior...the final result...of recursive calls to your method. However, the recursive calls don't do anything to affect the result of the initial execution of the method. If we look at the few lines that matter at the end of your method:
if same(s):
output += s[0]
self.longestCommonPrefix(slicer(strs), output)
return output
The problem here is that since output is immutable, its value won't be changed by calling longestCommonPrefix recursively. So from the standpoint of the outermost call to longestCommonPrefix, the result it will return is determined only by if same(s) is true or false. If it is true it will return s[0], otherwise it will return ''.
The easiest way to fix this behavior and have your recursive call affect the result of the prior call to the method would be to have its return value become the value of output, like this:
if same(s):
output += s[0]
output = self.longestCommonPrefix(slicer(strs), output)
return output
This is a common code pattern when using recursion. Just this change does seem to give you the result you expect! I haven't analyzed your whole algorithm, so I don't know if it becomes "correct" with just this change.
Can you try this? I
class Solution(object):
def longestCommonPrefix(self, strs, output = ''):
#return true if all chars in string are the same
def same(s):
return s == len(s) * s[0]
#return new list of strings with first char removed from each string
def slicer(list_, list_2 = []):
for string in list_:
string1 = string[1:]
list_2.append(string1)
return list_2
#return string containing first char from each string
def puller(list_):
s = ''
for string in list_:
s += string[0]
return s
#pull first character from each string
s = puller(strs)
# Can you Try this revision?
# I think the problem is that your new version of output is being lost when the fourth called function returns to the third and the third returns to the second, etc...
# You need to calculate a new output value before you call recursively, that is true, but you also need a way to 'store' that output when that recursively called function 'returns'. Right now it disappears, I believe.
if same(s):
output += s[0]
output = self.longestCommonPrefix(slicer(strs), output)
return output
The title is pretty self explanatory. The output only prints out the first letter of the string. I don't know what I'm doing wrong.
string = "hello"
def string_loop(string):
for x in string:
return(x)
print(string_loop(string))
output: h
Problem: Currently, your method is taking in a value string and iterating through it, however as it iterates over the first element, it will return it therefore ending the method call.
def string_loop(string):
for x in string:
return(x)
When you iterate through a string, unlike other collections (lists, dictionaries, ...) python unpacks it into an array of characters so the first element of the array is the first character which is why you only return "h".
Solution:
1) If you wanted to print each character of your string, you have two options:
a) Simply print inside your method with no return value.
def string_loop(string):
for character in string:
print(character)
string_loop("hello")
b) Add your characters to a list and print out the list returned by the method.
def string_loop(string):
my_list = list()
for character in string:
list.append(character)
print(string_loop("hello"))
2) On the other hand, if you were trying to print out every string while iterating through a list of strings, you would could iterate through the individual strings in the list
def string_loop(string_list):
for string in string_list:
print(string)
print(string_loop(["hello","world"]))
I have been tasked with trying to recreate the methods of an ArrayList type for python. I have been successful in recreating everything except for the str and the repr function, but since they behave mostly the same I only need help with one. Below is my code for the method, but I keep getting a Type Error stating "can only join an iterable"
def __str__(self):
"""Implements `str(self)`. Returns '[]' if the list is empty, else
returns `str(x)` for all values `x` in this list, separated by commas
and enclosed by square brackets. E.g., for a list containing values
1, 2 and 3, returns '[1, 2, 3]'."""
str= '['
if len(self.data)>0:
for i in range(len(self.data)):
if i ==0:
str1 = str+''.join(self[i])
else:
str1 = str+','+ ''.join(self[i])
return str1+']'
else:
return '[]'
There is just one catch to all of this, and that is that I can only call the following methods to help, though this should not be a limitation for this method. Please Help!
Methods:
lst[i] for getting and setting a value at an existing, positive index i
len(lst) to obtain the number of slots
lst.append(None) to grow the list by one slot at a %time
del lst[len(lst)-1] to delete the last slot in a list
The key is that you can use str() on the elements of the list; since your __str__() isn't calling str(self), you won't have infinite recursion.
Here is one way to do it.
#UNTESTED
def __str__(self):
"""Implements `str(self)`. Returns '[]' if the list is empty, else
returns `str(x)` for all values `x` in this list, separated by commas
and enclosed by square brackets. E.g., for a list containing values
1, 2 and 3, returns '[1, 2, 3]'."""
# Assuming that SELF implements iteration
return '[' + ', '.join(str(x) for x in self) + ']'
# Assuming that iteration isn't implemented
return '[' + ', '.join(str(self[i]) for i in range(len(self))) + ']'
I'm having problems with a homework question.
"Write a function, to_str(a), that takes an array, a, converts each of
its elements to a string (using str(a[i])) and appends all these
strings together."
This is what I have
def to_str(a):
for i in a: a.append([i])
return str(a[i])
I have no idea how to use str(a[i]), I was wondering if someone can point me to the right direction
From the docs:
str(object) -> string
Return a nice string representation of the object. If the argument is
a string, the return value is the same object.
So str(a[i]) will return a string representation of a[i], i.e. convert a[i] to a string.
You will then need to concatenates the strings for all values of i.
As for your code, I have the following comments:
i is an element of a, not an index, as you might be thinking;
you are appending elements of a to a (endlessly, I'm afraid);
a[i] can cause an exception, because, like I said, i is an element, not an index;
you need to return a concatenation of strings, not a string from one element.
Also, if using str(a[i]) is not strictly mandatory, I'd suggest to skip it as unpythonic. You don't need indexes at all for this. Examples:
''.join(str(element) for element in a)
or
''.join(map(str, a))
will return what you need. In both cases str is applied to all elements of a.
The simplest-to-understand ("beginner") way without using indexes will be
s = ''
for element in a:
s += str(element)
return s
It's a bit less efficient, though it does effectively the same thing.
Converting each element into a string is easiest to use list comprehension:
[ str(i) for i in a ]
# equivalent to
[ str(a[i]) for i in range(len(a)) ]
# equivalent to
map(str, a) # most concise, use if you want to feel incredibly clever...
So you can write the function:
def to_str2(a):
''.join([str(i) for i in a]) # concatenates the list as a list of strings
.
Your code nearly does this:
def to_str(a):
new_a = [] # rather than use the same a!
for i in a:
new_a.append(str(i)) #convert i to string before appending
return new_a
The code meeting all the task criteria is rather something like:
def to_str(a):
return reduce(lambda x, y: x + str(y), a, '')
Which does things exactly in the mentioned way: first converts them to strings, then adds to the string made from already processed elements (which at the beginning is just emty string).
EDIT: The clearer (and supported by Python 3) way is to use explicit looping through elements. It does exactly the same, clarifying at the same time how reduce() works:
def to_str(a):
result = '' # third argument of reduce()
for item in a:
result += str(item) # does what reduce() lambda argument was doing
return result
the simplest way is:
[str(i) for i in a]
if you want a function:
def to_str(a):
return [str(i) for i in a]
This question already has answers here:
Convert a String representation of a Dictionary to a dictionary
(11 answers)
How to convert string representation of list to a list
(19 answers)
Closed last month.
Say I have a string that's of the same form a tuple should be, for example, "(1,2,3,4,5)". What's the easiest way to convert that into an actual tuple? An example of what I want to do is:
tup_string = "(1,2,3,4,5)"
tup = make_tuple(tup_string)
Just running tuple() on the string make the whole thing one big tuple, whereas what I'd like to do is comprehend the string as a tuple. I know I can use a regex for this, but I was hoping there's a less costly way. Ideas?
It already exists!
>>> from ast import literal_eval as make_tuple
>>> make_tuple("(1,2,3,4,5)")
(1, 2, 3, 4, 5)
Be aware of the corner-case, though:
>>> make_tuple("(1)")
1
>>> make_tuple("(1,)")
(1,)
If your input format works different than Python here, you need to handle that case separately or use another method like tuple(int(x) for x in tup_string[1:-1].split(',')).
I would recommend using literal_eval.
If you are not comfortable with literal_eval or want to have more control on what gets converted you can also disassemble the string, convert the values and recreate the tuple.
Sounds more complicated than it is, really, it's a one-liner:
eg = '(102,117,108)'
eg_tuple = map(int, eg.replace('(','').replace(')','').split(',')))
This would throw a ValueError if any element (string) in the tuple is not convertible to int, like, for example the '1.2' in the string: '(1.2, 3, 4)'.
The same can be achieved with regex:
import re
eg = '(102,117,108)'
et_tuple = tuple(map(int, re.findall(r'[0-9]+', eg)))
You can parse your string without SyntaxError
def parse_tuple(string):
try:
s = eval(string)
if type(s) == tuple:
return s
return
except:
return
This function return the Tuple if parse is success. Otherwise return None.
print parse_tuple("('A', 'B', 'C')")
Simplest way to do this (without ast):
def _make_tuple(self, val: str) -> tuple:
"""
Convert a string representation of a tuple to a tuple.
Example:
"('item1', 'item2')" -> ('item1', 'item2')
"""
return tuple(v.lstrip("('").rstrip("')") for v in val.split(", "))
We can also parse it by ourself.
Let's say we have tuple returned by Python like below:
((2, 'C/C++', 0, 'clang_cpp'), (3, 'Python相关', 0, 'python'))
Here're how we do it
First, we keep reading the characters in the tuple string but stores the last left semicolon's position and how many semicolons we have meet (we can call it left semicolon level, as so for right semicolons), whenever we meet a right semicolon, we do things below:
Take a substring from last semicolon to current right semicolon.(In
this substring, there is no more semicolons, we just split it into
array by ",". Let's say the new array is M)
Then we append M to our result array, which array will stores allM.
Thirdly, delete the substring we taken from the original string.
Finally, do the same things like step 1 till the right and left
semicolon's level comes to 0.
JavaScript code is like below:
function parseTuple(t){
var lc = "(";
var rc = ")";
var lc_level = 0;
var rc_level = 0;
var last_lc = 0;
var last_rc = 0;
var result = [];
for(i=0;i<t.length;i++){
if(t[i] == lc){
lc_level++;
last_lc = i;
}else if(t[i] == rc){
rc_level++;
last_rc = i;
}
if(rc_level == 1){
var substr = t.slice(last_lc+1,last_rc);
var data = substr.split(",");
result.push(data);
lc_level--;
rc_level--;
i = 0;
t = t.slice(0,last_lc) + t.substring(last_rc+1);
}
if(lc_level == rc_level && lc_level==0){
break;
}
}
return result;
}