sort algorithm implemented in Python has problem - python

I want to sort Strings in ascending order.
For example, s = 'Zbcdefg' returns answer 'gfedcbZ'
def solution(s):
answer = ''
while True:
max = s[0]
for j in range(1,len(s)):
if ord(max) < ord(s[j]):
max = s[j]
answer += max
s= s.replace(max,'')
if len(s) == 1:
answer += s[0]
break
return answer
This is my code but some test cases are not solved with this. I don't know why. Can you find any logical error in this code?

The problem of this code was in s = s.replace(max,''). If a character searched as a highest order is stored as max (even though the name is not that proper bcz it can overwrite built in func) and pop it out from the original string s using s.replace(max,''), the problem is that method can delete the unexpected character(s) which is the same as max but not the max that I found.
Therefore, I fixed it as s.replace(max,'',1) to replace only one character firstly matched in string s.

Related

Recursively searching for a string in a list of characters

I have a problem to solve which is to recursively search for a string in a list (length of string and list is atleast 2) and return it's positions. for example: if we had ab with the list ['a','b','c'], the function should return '(0,2)', as ab starts at index 0 and ends at 1 (we add one more).
if we had bc with the same list the function should return '(1,3)'.
if we had ac with the same list the function should return not found.
Note that I'm solving a bigger problem which is to recursively search for a string in a matrix of characters (that appears from up to down, or left to right only), but I am nowhere near the solution, so I'm starting by searching for a word in a row of a matrix on a given index (as for searching for a word in a normal list), so my code might have char_mat[idx], treat it as a normal list like ['c','d','e'] for example.
Note that my code is full of bugs and it doesn't work, so I explained what I tried to do under it.
def search_at_idx(search_word, char_mat, idx, start, end):
if len(char_mat[idx]) == 2:
if ''.join(char_mat[idx]) == search_word:
return 0,2
else:
return 'not found', 'not found'
start, end = search_at_idx(search_word, char_mat[idx][1:], idx, start+1, end)
return start, end
The idea of what I tried to do here is to find the base of the recursion (when the length of the list reaches 2), and with that little problem I just check if my word is equal to the chars when joined together as a string, and return the position of the string if it's equal else return not found
Then for the recursion step, I send the list without the first character, and my start index +1, so if this function does all the job for me (as the recursion hypothesis), I need to check the last element in the list so my recursion works. (but I don't know really if this is the way to do it since the last index can be not in the word, so I got stuck). Now I know that I made alot of mistakes and I'm nowhere near the correct answer,I would really appreciate any explanation or help in order to understand how to do this problem and move on to my bigger problem which is finding the string in a matrix of chars.
I've thrown together a little example that should get you a few steps ahead
char_mat = [['c', 'e', 'l', 'k', 'v'],]
search_word = 'lk'
def search_at_idx(search_word, char_mat, idx, start=0):
if len(char_mat[idx]) < len(search_word):
return 'not', 'found'
if ''.join(char_mat[idx][:len(search_word)]) == search_word:
return start, start+len(search_word)
char_mat[idx] = char_mat[idx][1:]
start, end = search_at_idx(search_word, char_mat, idx, start+1)
return start, end
print(search_at_idx(search_word, char_mat, 0))
To point out a few errors of yours:
In your recursion, you use char_mat[idx][1:]. This will pass a slice of the list and not the modified matrix. That means your next call to char_mat[idx] will check the letter at that index in the array. I'll recommend using the debugger and stepping through the program to check the contents of your variables
Instead of using start and end, you can always assume that the found word has the same length as the word you are searching for. So the distance you have to look is always start + len(search_word)
If you have any additional questions about my code, please comment.
Here's an example for list comprehension if that counts as loophole:
foundword = list(map("".join, list(zip(*([char_mat[idx][i:] + list(char_mat[idx][i-1]) for i in range(len(search_word))])))[:-1])).index(search_word)
print((foundword, foundword + len(search_word)) if foundword else 'Not found')
l = ["a","b","c"]
def my_indexes(pattern, look_list, indx_val):
if pattern == "".join(look_list)[:2]:
return indx_val, indx_val+1
else:
if len(look_list) == 2:
return None
return my_indexes(pattern, look_list[1:],indx_val+1)
print(my_indexes("bc",l,0))
Two options:
1.We find the case we are looking for, so the first two elements of our list are "ab", or
2. "a" and "b" are not first two elements of our list. call the same function without first element of the list,and increase indx_val so our result will be correct.We stop doing this when the len(list) = 2 and we didn't find a case. (assuming we're looking for length of 2 chars)
edit: for all lengths
l = ["a","b","c","d"]
def my_indexes(pattern, look_list, indx_val):
if pattern == "".join(look_list)[:len(pattern)]:
return indx_val, indx_val+len(pattern) # -1 to match correct indexes
else:
if len(look_list) == len(pattern):
return None
return my_indexes(pattern, look_list[1:],indx_val+1)
print(my_indexes("cd",l,0))

How do I find what is similar in multiple strings in python?

I want to get what is similar in a few strings. For example, I have 6 strings:
HELLO3456
helf04g
hell0r
h31l0
I want to get what is similar in these strings, for example in this case I would like it to tell me something like:
h is always at the start
That example is pretty simple and I can figure that out in my head but with something like:
61TvA2dNwxNxmWziZxKzR5aO9tFD00Nj
pHHlgpFt8Ka3Stb5UlTxcaEwciOeF2QM
fW9K4luEx65RscfUiPDakiqp15jiK5f6
17xz7MYEBoXLPoi8RdqbgkPwTV2T2H0y
Jvt0B5uZIDPJ5pbCqMo12CqD7pdnMSEd
n7voYT0TVVzZGVSLaQNRnnkkWgVqxA3b
it's not that easy. I have seen and tried:
Find the similarity metric between two strings
how to find similarity between many strings and plot it
to name a few but they're all not what I'm looking for. They give a value of how similar they are and I need to know what is similar in them.
I want to know if this is even possible and if so, how I can do it. Thank you in advance.
Minimal Solution
You are on the correct soltuion path with the difflib Library. I just picked the first two examples from your question to create a minimal Solution.
from difflib import SequenceMatcher
a = "61TvA2dNwxNxmWziZxKzR5aO9tFD00Nj"
b = "pHHlgpFt8Ka3Stb5UlTxcaEwciOeF2QM"
Sequencer = SequenceMatcher(None, a, b)
print(Sequencer.ratio())
matches = Sequencer.get_matching_blocks()
print(matches)
for match in matches:
idx_a = match.a
idx_b = match.b
if not (idx_a == len(a) or idx_b == len(b)):
print(30*'-' + 'Found Match' + 30*'-')
print('found at idx {} of str "a" and at idx {} of str "b" the value {}'.format(idx_a, idx_b, a[idx_a]))
Output:
0.0625
[Match(a=2, b=18, size=1), Match(a=5, b=29, size=1), Match(a=32, b=32, size=0)]
------------------------------Found Match------------------------------
found at idx 2 of str "a" and at idx 18 of str "b" the value T
------------------------------Found Match------------------------------
found at idx 5 of str "a" and at idx 29 of str "b" the value 2
Explanation
I just used the ratio() to see if any similarity is existing. The function get_matching_blocks() returns a list with all matches in your string sequence. My minimal Solution doesn't care for same position, but this should be an easy fix with checking the indices. In the Situation that the return value of ratio() is rqual to 0.0 the matcher does not generate an empty list. The list contains always a match for the end of Sequence. I worked around with checking against length of the sequence with the matching idices. Another solution is to use only matches with a size > 0, as shown below:
if match.size > 0:
...
My Example also doesn't handle matches with size > 1. I think you will figure out to handle this problem ;)
I think this should be your desire solution. I have added "a" at the start of every string because otherwise there is no similarity in the strings you mentioned.
lst = ["A61TvA2dNwxNxmWziZxKzR5aO9tFD00Nj","apHHlgpFt8Ka3Stb5UlTxcaEwciOeF2QM","afW9K4luEx65RscfUiPDakiqp15jiK5f6","a17xz7MYEBoXLPoi8RdqbgkPwTV2T2H0y", "aJvt0B5uZIDPJ5pbCqMo12CqD7pdnMSEd","an7voYT0TVVzZGVSLaQNRnnkkWgVqxA3b"]
total_strings = len(lst)
string_length = len(lst[0])
for i in range(total_strings):
lst[i] = lst[i].lower()
for i in range(string_length):
flag = 0
lst_char = lst[total_strings-1][i]
for j in range(total_strings-1):
if lst[j][i] == lst_char:
flag = 1
continue
else:
flag = 0
break
if flag == 1:
print(lst[total_strings-1][i]+" is always at position "+str(i))

Python :string index out of range with trying to find first capital letter

I am trying to get the first capital letter in the string but I am getting an index out of range error I don't know if it is my base case for the recursion. Please can someone help me
This is my code:
def firstCapital(str, i):
if (str[i] == None):
return 0
if (str[i].isupper()):
return str[i]
return firstCapital(str, i + 1)
name = "geoRge"
res = firstCapital(name, 0)
if (res == 0):
print("No uppercase letter")
else:
print(res)
str[i] will raise this index out of range exception if i is greater or equal to the length of str. You should change your base case to:
if (i >= len(str)):
return 0
The line if (str[i] == None): doesn't do what you want it to do. This seems like it's trying to check if your index is off the end of the string, but strings in Python don't have None after the last real character. Rather, you get exactly the exception you describe when you try to index past the end.
Instead, you should be comparing i to len(str), which is the length of the string as a number. Since indexes start at zero, an index equal to len(str) is just past the end, so you probably want:
if i >= len(str):
return 0
I'd also double check if returning zero is what you want to do there. If you find a capital letter, you're returning it from your other conditional case. It's not always ideal to return different types in different situations, as it can be tricky for the caller to know what APIs they can use on the result. Returning an empty string, or None might make more sense than returning a number.
using str[i]==None will 'force' python to determine the value of str[i], which doesn't exist, thus the index out of range error. You can determine that you reached the end of the string using len(str) and i instead:
def firstCapital(str, i):
if i>len(str)-1: #Instead of str[i]==None
return 0
if str[i].isupper():
return str[i]
return firstCapital(str, i + 1)
input : ('Ali',0)
Output: 'A'
Input: ('lia',0)
Output:0

Python 2.7 "list index out of range"

I keep getting "IndexError: list index out of range", the code does fine with things like "s = 'miruxsexxzlbveznyaidekl'" but this particular length makes it throw an error. Can anyone help me understand what I did wrong here, not just give me the answer? (I'd like to not have to come back and ask more question haha)
__author__ = 'Krowzer'
s = 'abcdefghijklmnopqrstuvwxyz'
def alpha(x):
current_substring = []
all_substring = []
for l in range(len(x) - 1):
current_substring.append(x[l])
if x[l + 1] < x[l]:
all_substring.append(current_substring)
#print("current: ", current_substring)
current_substring = []
#print(all_substring)
largest = all_substring[0]
for i in range(len(all_substring)):
if len(all_substring[i]) > len(largest):
largest = all_substring[i]
answer = ''.join(largest)
print('Longest substring in alphabetical order is: ' + answer )
alpha(s)
I can try to explain what is going on.
You are trying to find the longest substring in alphabetical order by looking for the end of the substring. Your definition of end is that there is a character less than the last character in the string -- something in descending alphabetical order.
Your example substring has no such string. So, the initial loop never finds an end to it. As a result, all_substring[] is empty and trying to get any element out of it (such as all_substring[0]) generates an error.
You can fix the code yourself. The easiest is probably just to check if it is empty. If so, then the entire original string is the match.
EDIT:
On second thought, there are two errors in the code. One is that the last character is not being considered. The second is that the final substring is not being considered.
def alpha(x):
current_substring = []
all_substring = []
for l in range(len(x)):
current_substring.append(x[l])
if l < len(x) - 1 and x[l + 1] < x[l]:
all_substring.append(current_substring)
#print("current: ", current_substring)
current_substring = []
print(all_substring)
all_substring.append(current_substring)
largest = all_substring[0]
for i in range(len(all_substring)):
if len(all_substring[i]) > len(largest):
largest = all_substring[i]
answer = ''.join(largest)
print('Longest substring in alphabetical order is: ' + answer )

finding the index of the first letter of a sub string in the main string

I am trying to find the index of the first letter of a sub string within the main string. The function acts exactly like the find method of python. I have created a find_chr function that gives me the index of a character in a string and I am using the find_chr to get the index of the substring.
def find_str(s,x):
i=0
if x in s:
return find_chr(s,x[i])
else:
return -1
My problem is that when I am using the string "IS GOING GOING" and substring as "ING", I am getting the index of the first "I", when I am expecting the index of the "I" of "ING". I will appreciate any input about changing the function to get the right index of the first letter of the substring.
In find_str you call find_chr(s,x[i]). This is calling find_chr with only x[i] (the ith part of the substring).
This should fix your problem
def find_chr(s,char):
i=0
step = len(char)
for j in range(len(s)+1):
ch = s[j:j+step]
if ch==char:
return (i)
break
i+=1
return -1
def find_str(s,x):
i=0
if x in s:
return find_chr(s,x)
else:
return -1
You aren't looping through the characters, you only check for i == 0 (i.e. the first character in s). You need to apply a "window" to the string, checking len(s) characters in a row:
def find_str(s, x):
if x in s: # is x present?
for i in range(len(s)): # work through string indices
if s[i:i+len(x)] == x: # does x start at current index?
return i
return -1
This should solve your problem:
def find_str(s, x):
i = 0
while i < len(s):
if s[i:i + len(x)] == x:
return i
else:
i += 1
print find_str('IS GOING GOING', 'ING')
Look up the use of the index function in strings. You will then happily replace all of that code with about 1 line.
Supplying the answer because of the following comments. Seriously though, if one is going to learn python, it is a good exercise to be aware of the methods available for an object.
>>> 'is going going'.index('ing')
5
or more generally
>>> fullstring.index(substring)
This should be marked as the correct answer because it is the simplest and most obviously correct. The complexity of the algorithms offered is way too high for this problem.
If the substring is not in the fullstring, a ValueError exception will be raised. So if you need a function, then it should return the index from a try or -1 (or None) from the except blocks.

Categories