I am writing a function to grow a tree:
def collect_append(collect,split):
collect.append(split)
return collect
def tree(string,passwords,collect): #collect is a list and passwords is also a list
matching_list = []
match = 0
if len(string)==0:
print(collect)
return 0
for j in passwords:
for i in range(min(len(j),len(string))):
if string[i]!=j[i]:
break
else :
matching_list.append(j)
match = match + 1
if match == 0:
return 1
else:
for split in matching_list:
x =tree(string.strip(split),passwords,collect_append(collect,split))
return x
My question is, for each split in matching_list(say two), I want to add different strings to the existing list at that point (i.e. I want two versions of list).
In this case the collect_append function I use is modifying the list in first iteration of the for loop and using the same for further iterations. What I want is to just modify the collect list just for the parameter and without permanently changing it. Is there a way to do this?
I see two serious errors in your code. First, this else clause is never executed:
for j in passwords:
for i in range(...):
if ...:
break
else:
...
Since the break is in the inner for loop, the outer for loop is never exited via a break so the else is never taken. Second, this doesn't do what you want:
string.strip(split)
You're trying to remove split from the beginning of string but you're removing all the letters in split from both ends of string, bruising it badly. Here's one way to do it correctly:
string[len(split):]
I'm going to go out on a limb, and rewrite your code to do what I think you want it to do:
def tree(string, passwords, collect):
length = len(string)
if length == 0:
return False
matching_list = []
for j in passwords:
i = min(len(j), length)
if string[:i] == j[:i]:
matching_list.append(j)
if not matching_list:
return False
result = False
for split in matching_list:
local_collection = list([split])
if split == string or tree(string[len(split):], passwords, local_collection):
collect.append(local_collection)
result = True
return result
collection = []
print(tree('dogcatcher', ['cat', 'catch', 'cher', 'dog', 'dogcat', 'dogcatcher', 'er'], collection))
print(collection)
OUTPUT
% python3 test.py
True
[['dog', ['cat', ['cher']], ['catch', ['er']]], ['dogcat', ['cher']], ['dogcatcher']]
%
Giving you a tree of all the ways to assemble string from the words in passwords.
Related
I'm doing a practice problem where I need to find the longest common prefix in a list of strings.
Example:
Input: strs = ["flower","flow","flight"]
Output: "fl"
I'm approaching this as follows:
def my_function(strs):
### get the length of shortest string in list and assign to "window"
min_len = min([len(x) for x in strs])
window = min_len
### chop all items in list to length of shortest item
for i in range(window):
if window == 0:
return ''
strs = [x[:window] for x in strs]
### Check the length of the set() of all items. If it's longer than 1,
### shorten the window and re-check
if len(set(strs)) == 1:
answer = list(set(strs))
return answer[0]
else:
window += -1
When I use the test case given above, my function returns:
fl
fl
Why am I getting this duplication?
You're using a weird loop where you increment "window" with the "for", but decrement it based on a condition. This causes an inconsistent iteration.
Either use a while loop and modify the counter manually, or use a for loop and don't modify the counter.
That said your approach of not so efficient, rather check the characters in parallel position after position:
def prefix(strs):
out = []
for x in zip(*strs):
if len(set(x)) == 1:
out.append(x[0])
else:
break
return ''.join(out)
prefix(strs)
Output: 'fl'
With #mozway's help, I was able to successfully execute the function using a while statement:
def prefix(strs):
min_len = min([len(x) for x in strs])
window = min_len
for i in range(window):
while window > 0:
strs = [x[:window] for x in strs]
if len(set(strs)) == 1:
answer = list(set(strs))
return answer[0]
else:
window += -1
return ''
def lengthgood(x):
for i in x:
if len(i)<13
return i
else:
pass
def makeproperlist(x):
return x.split(',')
attendancelist=makeproperlist(input("attendee list:"))
final_list=list(filter(lengthgood,attendancelist))
for i in finallist:
print (i)
I want to write a programme of which I create a list in which only elements shorter than 14 can be a part of.
This is my code, but it keeps returning all the elements I put in, even if some of them are longer than 14?
I tried to print the len(i) and it says that it is 1 for every element in the list?
How do I solve this?
You shouldn't put a return within a loop; it'll only return the first element that matches your condition.
You also shouldn't be looping within your filter function, because you're actually looping over characters of strings, which are all length 1.
Therefore, the first character is always returning a truthy value, giving you back the initial input after filtering
You only need to check the input length, and filter functions should ideally return appropriate boolean conditions rather than truthy values (in your case return i is returning a non-empty string)
def lengthgood(x):
return len(x)<13
If you don't need to use filter(), you can write a list comprehension
final_list=[a if len(a) < 13 for a in attendancelist]
may be like that
flst = []
def croper(lst):
for i in lst:
flst.append(i) if len(i) < 13 else 0
lst = input("attendee list:").split(',')
croper(lst)
print(flst)
or shorter
def croper(lst):
return [i for i in lst if len(i) < 13]
lst = input("attendee list:").split(',')
print(croper(lst))
You want to create a list but you not define it anywhere in program simply done it with simply one function makeproperlist(x).
Try this code bro this will help you.
attendancelist=[]
while (True):
ch=input("Enter c for continue and e for exit : ")
if (ch=='c'):
def makeproperlist(x):
if x<=13:
attendancelist.append(x)
else:
print("Enter number which is <= to 13.")
makeproperlist(int(input("attendee list:")))
elif (ch=='e'):
break;
print("Your attendece list : ",attendancelist)
I wanted to implement the code by using recursive function without for loop or while loop.
And I wanted to implement function called go_through() and take two parameters as a list(list1) and an integer(letters) so that if the element of each length of string has bigger or equal to integer, I replace it using the other function called replace_it()
def go_through(list1, letters):
get_list = list1[:]
num =len(list1)
index = 0
if index != num:
if len(get_list[0]) >= letters:
get_list += replace_it(get_list[0])
index += 1
print(get_list, 'True')
return go_through(get_list[1:], letters)
else:
get_list += [get_list[0]]
index += 1
print(get_list, 'False')
return go_through(get_list[1:], letters)
else:
print(get_list)
def replace_it(string):
if string == 'pineapple':
return ['peach', 'and', 'pear']
if string== 'delicious':
return ['really', 'gross']
go_through(['pineapple','is','delicious','I', 'want', 'it'],7)
should be looking like
peach and pear is really gross I want it
So I have a problem for this codes
It doesn't allow me to stop print as what I want to print is one line
The result would be looking like the picture I attached
But I want to stop where I highlighted and return it as it is the same output what I wrote above.
How can I fix this problem?
The list is not reducing at any point. get_list += [get_list[0]] in the else block keeps the list the same size when followed by return go_through(get_list[1:], letters), while get_list += replace_it(get_list[0]) in the if will always extend the list.
Maybe you meant something like
else:
# this isn't needed
# get_list += [get_list[0]]
return go_through(get_list[1:], letters)
Also, it seems that you're getting the list order mixed up in the first bit maybe.
if len(get_list[0]) >= letters:
# this is adding the new list at the end, not replacing the word
# get_list += replace_it(get_list[0])
# you can send the shortened list to the function again,
# and stick the replacement words at the start
return replace_it(get_list[0]) + go_through(get_list[1:], letters)
we've started doing Lists in our class and I'm a bit confused thus coming here since previous questions/answers have helped me in the past.
The first question was to sum up all negative numbers in a list, I think I got it right but just want to double check.
import random
def sumNegative(lst):
sum = 0
for e in lst:
if e < 0:
sum = sum + e
return sum
lst = []
for i in range(100):
lst.append(random.randrange(-1000, 1000))
print(sumNegative(lst))
For the 2nd question, I'm a bit stuck on how to write it. The question was:
Count how many words occur in a list up to and including the first occurrence of the word “sap”. I'm assuming it's a random list but wasn't given much info so just going off that.
I know the ending would be similar but no idea how the initial part would be since it's string opposed to numbers.
I wrote a code for a in-class problem which was to count how many odd numbers are on a list(It was random list here, so assuming it's random for that question as well) and got:
import random
def countOdd(lst):
odd = 0
for e in lst:
if e % 2 = 0:
odd = odd + 1
return odd
lst = []
for i in range(100):
lst.append(random.randint(0, 1000))
print(countOdd(lst))
How exactly would I change this to fit the criteria for the 2nd question? I'm just confused on that part. Thanks.
The code to sum -ve numbers looks fine! I might suggest testing it on a list that you can manually check, such as:
print(sumNegative([1, -1, -2]))
The same logic would apply to your random list.
A note about your countOdd function, it appears that you are missing an = (== checks for equality, = is for assignment) and the code seems to count even numbers, not odd. The code should be:
def countOdd(lst):
odd = 0
for e in lst:
if e%2 == 1: # Odd%2 == 1
odd = odd + 1
return odd
As for your second question, you can use a very similar function:
def countWordsBeforeSap(inputList):
numWords = 0
for word in inputList:
if word.lower() != "sap":
numWords = numWords + 1
else:
return numWords
inputList = ["trees", "produce", "sap"]
print(countWordsBeforeSap(inputList))
To explain the above, the countWordsBeforeSap function:
Starts iterating through the words.
If the word is anything other than "sap" it increments the counter and continues
If the word IS "sap" then it returns early from the function
The function could be more general by passing in the word that you wanted to check for:
def countWordsBefore(inputList, wordToCheckFor):
numWords = 0
for word in inputList:
if word.lower() != wordToCheckFor:
numWords = numWords + 1
else:
return numWords
inputList = ["trees", "produce", "sap"]
print(countWordsBeforeSap(inputList, "sap"))
If the words that you are checking come from a single string then you would initially need to split the string into individual words like so:
inputString = "Trees produce sap"
inputList = inputString.split(" ")
Which splits the initial string into words that are separated by spaces.
Hope this helps!
Tom
def count_words(lst, end="sap"):
"""Note that I added an extra input parameter.
This input parameter has a default value of "sap" which is the actual question.
However you can change this input parameter to any other word if you want to by
just doing "count_words(lst, "another_word".
"""
words = []
# First we need to loop through each item in the list.
for item in lst:
# We append the item to our "words" list first thing in this loop,
# as this will make sure we will count up to and INCLUDING.
words.append(item)
# Now check if we have reached the 'end' word.
if item == end:
# Break out of the loop prematurely, as we have reached the end.
break
# Our 'words' list now has all the words up to and including the 'end' variable.
# 'len' will return how many items there are in the list.
return len(words)
lst = ["something", "another", "woo", "sap", "this_wont_be_counted"]
print(count_words(lst))
Hope this helps you understand lists better!
You can make effective use of list/generator comprehensions. Below are fast and memory efficient.
1. Sum of negatives:
print(sum( i<0 for i in lst))
2. Count of words before sap: Like you sample list, it assumes no numbers are there in list.
print(lst.index('sap'))
If it's a random list. Filter strings. Find Index for sap
l = ['a','b',1,2,'sap',3,'d']
l = filter(lambda x: type(x)==str, l)
print(l.index('sap'))
3. Count of odd numbers:
print(sum(i%2 != 0 for i in lst))
I have a list of sublists each of which consists of one or more strings. I am comparing each string in one sublist to every other string in the other sublists. This consists of writing two for loops. However, my data set is ~5000 sublists, which means my program keeps running forever unless I run the code in increments of 500 sublists. How do I change the flow of this program so I can still look at all j values corresponding to each i, and yet be able to run the program for ~5000 sublists. (wn is Wordnet library)
Here's part of my code:
for i in range(len(somelist)):
if i == len(somelist)-1: #if the last sublist, do not compare
break
title_former = somelist[i]
for word in title_former:
singular = wn.morphy(word) #convert to singular
if singular == None:
pass
elif singular != None:
newWordSyn = getNewWordSyn(word,singular)
if not newWordSyn:
uncounted_words.append(word)
else:
for j in range(i+1,len(somelist)):
title_latter = somelist[j]
for word1 in title_latter:
singular1 = wn.morphy(word1)
if singular1 == None:
uncounted_words.append(word1)
elif singular1 != None:
newWordSyn1 = getNewWordSyn(word1,singular1)
tempSimilarity = newWordSyn.wup_similarity(newWordSyn1)
Example:
Input = [['space', 'invaders'], ['draw']]
Output= {('space','draw'):0.5,('invaders','draw'):0.2}
The output is a dictionary with corresponding string pair tuple and their similarity value. The above code snippet is not complete.
How about doing a bit of preprocessing instead of doing a bunch of operations over and over? I did not test this, but you get the idea; you need to take anything you can out of the loop.
# Preprocessing:
unencountered_words = []
preprocessed_somelist = []
for sublist in somelist:
new_sublist = []
preprocessed_somelist.append(new_sublist)
for word in sublist:
temp = wn.morphy(word)
if temp:
new_sublist.append(temp)
else:
unencountered_words.append(word)
# Nested loops:
for i in range(len(preprocessed_somelist) - 1): #equivalent to your logic
for word in preprocessed_somelist[i]:
for j in range(i+1, len(preprocessed_somelist)):
for word1 in preprocessed_somelist[j]:
tempSimilarity = newWordSyn.wup_similarity(newWordSyn1)
you could try something like this but I doubt it will be faster (and you will probably need to change the distance function)
def dist(s1,s2):
return sum([i!=j for i,j in zip(s1,s2)]) + abs(len(s1)-len(s2))
dict([((k,v),dist(k,v)) for k,v in itertools.product(Input1,Input2)]
This is always going to have scaling issues, because you're doing n^2 string comparisons. Julius' optimization is certainly a good starting point.
The next thing you can do is store similarity results so you don't have to compare the same words repeatedly.
One other optimisation you can make is store comparisons of words and reuse them if the same words are encountered.
key = (newWordSyn, newWordSyn1)
if key in prevCompared:
tempSimilarity = prevCompared[(word, word1)]
else:
tempSimilarity = newWordSyn.wup_similarity(newWordSyn1)
prevCompared[key] = tempSimilarity
prevCompared[(newWordSyn1, newWordSyn)] = tempSimilarity
This only helps if you will see a lot of the same word combination, but i think wup_similarity is quite expensive.