Find the next iteration in loop python - python

I am trying to find out if given a string if 2 target characters follow one another. So essentially, I am trying to find if a character and its neighbor are target characters. How should I go about this? The following is what I have tried so far.
target_list=["t","a","r","g","e","t"]
for char in some_string:
if (char and some_string[some_string.index(char)+1]) in target_list:
print ("correct")
else:
print ("incorrect")
Expected output:
if some_string="heytr" == "correct"
if some_string="hyt" == "incorrect"
if some_string="heyt" == "incorrect"

Just go through the indices and process every pair of characters:
for i in range(len(some_string) - 1):
if some_string[i] in target_list and some_string[i+1] in target_list:
print ("correct")
break
if i == len(some_string) - 1:
print ("incorrect")
You can alternatively create a mapping and look for adjacent true positives:
m = [(char in target_list) for char in some_string]
for i in range(len(m) - 1):
if m[i] and m[i+1]:
print ("correct")
break
if i == len(m) - 1:
print ("incorrect")

Just use map:
target_list=['t','a','r','g','e']
def toDict(list):
mp = {}
for c in list:
mp[c] = True
return mp
d = toDict(target_list)
print("dict:" , d)
def check(string, mp):
count = 0
for c in string:
if(mp.get(c,False)):
count = count+1
if(count > 1):
return True
else:
count = 0
return False
print("check:" , check("heytr", d))
print("check:" , check("hyt", d))
print("check:" , check("heyt", d))

from itertools import tee
def rolling_window(iterable, n=2):
iterators = tee(iterable, n)
for i, iterator in enumerate(iterators):
for skip in range(i):
next(iterator, None)
return zip(*iterators)
def match(some_string, target, n=2):
target = set(target)
return any(target.issuperset(s) for s in rolling_window(some_string, n=n))

A regular expression solution.
import re
target_chars='target'
p = re.compile('[%s]{2}' % re.escape(target_chars))
m = p.search(some_string)
if m:
print('correct')
else:
print('incorrect')

You can also use any() and zip() for this:
target_list=["t","a","r","g","e","t"]
target_list = set(target_list)
some_strings = ["heytr", "hyt", "heyt"]
def match_strings(string, target_list):
return any(x in target_list and y in target_list for x, y in zip(string, string[1:]))
for some_string in some_strings:
if match_strings(some_string, target_list):
print("correct")
else:
print("incorrect")
Which Outputs:
correct
incorrect
incorrect
Logic of above code:
Converts target_list to a set, since set lookup is constant time. If you keep it as a list, then lookup time is linear.
Uses zip() to create pairs of the current element and the next element, and checks if both of these elements exist in target_list. Then checks if any() of the pairs exist, which returns True if any of the pairs exist, and False if none exist.
Then loop over all the strings in some_strings, and check the above for each one.

def judge(some_string):
for index in range(0,len(some_string)-1):
if some_string[index] in target_list and some_string[index+1] in target_list:
print("correct")
break
else:
print("incorrect")
judge("heytr") --correct
judge("hyt") -- incorrect
judge("heyt") --incorrect
For loop iterates on all character of the string checks if i and i+1 is present in target.if yes prints out correct. after all iterations of loop is over if no two character are found in target it comes to the else part of for loop and prints out incorrect.

Related

Find if an array contains a string with one mismatch

I want say there is a string in the list with only one mismatch
def check(list, s):
n = len(list)
# If the array is empty
if (n == 0):
return False
for i in range(0, n, 1):
# If sizes are same
if (len(list[i]) != len(s)):
continue
diff = False
for j in range(0, len(list[i]), 1):
if (list[i][j] != s[j]):
# If first mismatch
if (diff == False):
diff = True
# Second mismatch
else:
diff = False
break
if (diff):
return True
return False
This code is okay but it works slowly. How can I make it faster using a dictionary?
You can use zip() to pair up each character of two strings and sum() to count the number of mismatches. The any() function will allow you to check for a match over every item in the list:
def check(sList,string):
return any(len(string)==len(s) and sum(a!=b for a,b in zip(s,string))==1
for s in sList)
check(["abcd","cdef","efgh"],"xfgh") # True
check(["abcd","cdef","efgh"],"abdc") # False
This translates to the following basic for-loop:
def check(sList,string):
for s in sList:
if len(string) !=len(s): continue
if sum(a!=b for a,b in zip(s,string)) == 1:
return True
return False
[EDIT] to make this go a bit faster, the string comparisons can use zip() as an iterator so that the comparison doesn't need to go to the end of every string:
def check(sList,string):
for s in sList:
if len(string) !=len(s): continue
mismatch = (a!=b for a,b in zip(s,string)) # non-matching iterator
if not any(mismatch): continue # at least one
if any(mismatch): continue # no more after that
return True
return False

Recursive Elimination of Character Groups in a String in Python

Given a string with a series of Rs and Gs, search for a way to eliminate them by groups. You can ONLY eliminate if characters are grouped (at least 2).
Example 1: RGRRRGGGRR
v v v
RGRRRGGGRR = RGGGGRR = RRR = {empty}, thus there is a possible solution.
Example 2: GGGRGRGRG
v
GGGRGRGRG = RGRGRG, can no longer find groups, thus there is NO possible solution.
I made an initial recursive function but it ends with no solution even though there is a possible solution.
def fn(string, start):
l = len(string)
if l-start > 0:
counter, isPop = 0, False
if string[start] == 'R':
while counter + start < l and string[counter + start] == 'R': counter+=1
if counter > 1: # If there is the same letter adjacent to the current letter being checked, it will pop this group.
for i in range(counter):
string.pop(start)
isPop = True
if not isPop and start+counter == l: return False # Returns false if previous action did not pop and
else: return fn(string, 0 if isPop else start+counter) # Letter being checked is the last element (it means
# that there are still elements in the string that can
else: # no longer be grouped and eliminated.
while counter + start < l and string[counter + start] == 'G': counter+=1
if counter > 1:
for i in range(counter):
string.pop(start)
isPop = True
if not isPop and start+counter == len(string): return False
else: return fn(string, 0 if isPop else start+counter)
if string: return False
else: return True
ways = []
string = input()
for j in range(len(string)): # Iterates through every position in the list and calls the fn just to see if it is possible.
if True in ways: # If there is a possible solution, it breaks the loop and prints "possible"
break
ways.append(fn(list(string), j))
if True in ways: print("Possible")
else: print("Impossible")
Cases that my algo doesn't work (returns false but there is actually a way):
1. GGRRGRRRRGGGGRGRGG
v v v v v v
GGRRGRRRRGGGGRGRGG = GGRRGRRRRRGRGG = GGRRGGRGG = GGRRRGG = GGRRRGG = GGGG = {empty}
2. GRRRGRRRGRRRGRRRGR
v v v v v v
GRRRGRRRGRRRGRRRGR = GRRRGRRRGGRRRGR = GRRRGRRRGGGR = GRRRGRRRR = GGRRRR = RRRR = {empty}
You can use recursion with a generator. Additionally, applying itertools.groupby to produce groupings up front leads to a shorter solution:
from itertools import groupby as gb
def get_groups(s, chain=[]):
if not s:
yield chain+[s]
else:
r = [list(b) for _, b in gb(s)]
for i, a in enumerate(r):
if len(a) > 1:
t = ''.join(map(''.join, [*r[:i], *([] if i >= len(r) else r[i+1:])]))
yield from get_groups(t, chain+[s])
cases = ['RGRRRGGGRR', 'GGGRGRGRG', 'GGRRGRRRRGGGGRGRGG', 'GRRRGRRRGRRRGRRRGR']
for case in cases:
print(f'{case}: {any(get_groups(case))}')
Output:
RGRRRGGGRR: True
GGGRGRGRG: False
GGRRGRRRRGGGGRGRGG: True
GRRRGRRRGRRRGRRRGR: True
get_groups produces an empty list [] if there is no possible path whereby the input is completed reduced to an empty string by removing groupings, and a listing of all the possible paths to an empty string.
I believe your primary issue with respect to debugging this code is your coding style.
Besides being messy, you have ambiguous return situations; your 'R' and 'G' parallel blocks aren't identical; you fail to update the array length variable after popping the array; you appear to start the recursion at the wrong index.
The best I could come up with cleaning up your code is the following that passes one more case but still fails one:
def fn(characters, start):
length = len(characters)
if length - start > 0:
for character in ['R', 'G']:
counter = 0
isPop = False
if characters[start] == character:
while start+counter < length and characters[start+counter] == character:
counter += 1
if counter > 1:
# If there is the same letter adjacent to the current
# letter being checked, it will pop this group.
for _ in range(counter):
characters.pop(start)
isPop = True
length -= 1 # we've shortened the array
if not isPop and start+counter == length:
# Returns false if previous action did not pop and
# letter being checked is the last element (it means
# that there are still elements in characters that can
# no longer be grouped and eliminated.
return False
return fn(characters, start if isPop else start+counter)
if characters:
return False
return True
My own solution is akin to that of #Ajax1234 as far as groupby goes:
from itertools import groupby
def eliminate_groups(string):
if not string: # base case of recursion
return True
# "RGRRRGGGRR" -> ['R', 'G', 'RRR', 'GGG', 'RR']
groups = [''.join(g) for _, g in groupby(string)]
for index, group in enumerate(groups):
if len(group) < 2:
continue
reduced = groups[:index] + groups[index+1:] # a deficient copy
status = eliminate_groups(''.join(reduced))
if status: # one of the variants succeeded!
return status
return False # all of the variants failed!
if __name__ == '__main__':
strings = ["RGRRRGGGRR", "GGGRGRGRG", "GGRRGRRRRGGGGRGRGG", "GRRRGRRRGRRRGRRRGR"]
for string in strings:
print(string, eliminate_groups(string))
OUTPUT
> python3 test.py
RGRRRGGGRR True
GGGRGRGRG False
GGRRGRRRRGGGGRGRGG True
GRRRGRRRGRRRGRRRGR True
>

Code to output the first repeated character in given string?

I'm trying to find the first repeated character in my string and output that character using python. When checking my code, I can see I'm not index the last character of my code.
What am I doing wrong?
letters = 'acbdc'
for a in range (0,len(letters)-1):
#print(letters[a])
for b in range(0, len(letters)-1):
#print(letters[b])
if (letters[a]==letters[b]) and (a!=b):
print(b)
b=b+1
a=a+1
You can do this in an easier way:
letters = 'acbdc'
found_dict = {}
for i in letters:
if i in found_dict:
print(i)
break
else:
found_dict[i]= 1
Output:
c
Here's a solution with sets, it should be slightly faster than using dicts.
letters = 'acbdc'
seen = set()
for letter in letters:
if letter in seen:
print(letter)
break
else:
seen.add(letter)
Here is a solution that would stop iteration as soon as it finds a dup
>>> from itertools import dropwhile
>>> s=set(); next(dropwhile(lambda c: not (c in s or s.add(c)), letters))
'c'
You should use range(0, len(letters)) instead of range(0, len(letters) - 1) because range already stops counting at one less than the designated stop value. Subtracting 1 from the stop value simply makes you skip the last character of letters in this case.
Please read the documentation of range:
https://docs.python.org/3/library/stdtypes.html#range
There were a few issues with your code...
1.Remove -1 from len(letters)
2.Move back one indent and do b = b + 1 even if you don't go into the if statement
3.Indent and do a = a + 1 in the first for loop.
See below of how to fix your code...
letters = 'acbdc'
for a in range(0, len(letters)):
# print(letters[a])
for b in range(0, len(letters)):
# print(letters[b])
if (letters[a] == letters[b]) and (a != b):
print(b)
b = b + 1
a = a + 1
Nice one-liner generator:
l = 'acbdc'
next(e for e in l if l.count(e)>1)
Or following the rules in the comments to fit the "abba" case:
l = 'acbdc'
next(e for c,e in enumerate(l) if l[:c+1].count(e)>1)
If complexity is not an issue then this will work fine.
letters = 'acbdc'
found = False
for i in range(0, len(letters)-1):
for j in range(i+1, len(letters)):
if (letters[i] == letters[j]):
print (letters[j])
found = True
break
if (found):
break
The below code prints the first repeated character in a string. I used the functionality of the list to solve this problem.
def findChar(inputString):
list = []
for c in inputString:
if c in list:
return c
else:
list.append(c)
return 'None'
print (findChar('gotgogle'))
Working fine as well. It gives the result as 'g'.
def first_repeated_char(str1):
for index,c in enumerate(str1):
if str1[:index+1].count(c) > 1:
return c
return "None"
print(first_repeated_char("abcdabcd"))
str_24 = input("Enter the string:")
for i in range(0,len(str_24)):
first_repeated_count = str_24.count(str_24[i])
if(first_repeated_count > 1):
break
print("First repeated char is:{} and character is
{}".format(first_repeated_count,str_24[i]))

Alternate letters in a string - code not working

I am trying to make a string alternate between upper and lower case letters. My current code is this:
def skyline (str1):
result = ''
index = 0
for i in str1:
result += str1[index].upper() + str1[index + 1].lower()
index += 2
return result
When I run the above code I get an error saying String index out of range. How can I fix this?
One way using below with join + enumerate:
s = 'asdfghjkl'
''.join(v.upper() if i%2==0 else v.lower() for i, v in enumerate(s))
#'AsDfGhJkL'
This is the way I would rewrite your logic:
from itertools import islice, zip_longest
def skyline(str1):
result = ''
index = 0
for i, j in zip_longest(str1[::2], islice(str1, 1, None, 2), fillvalue=''):
result += i.upper() + j.lower()
return result
res = skyline('hello')
'HeLlO'
Explanation
Use itertools.zip_longest to iterate chunks of your string.
Use itertools.islice to extract every second character without building a separate string.
Now just iterate through your zipped iterable and append as before.
Try for i in range(len(str1)): and substitute index for i in the code. After, you could do
if i % 2 == 0: result += str1[i].upper()
else: result += str1[i].lower()
For every character in your input string, you are incrementing the index by 2. That's why you are going out of bounds.
Try using length of string for that purpose.
you do not check if your index is still in the size of your string.
It would be necessary to add a condition which verifies if the value of i is always smaller than the string and that i% 2 == 0 and that i == 0 to put the 1st character in Upper
with i% 2 == 0 we will apply the upper one letter on two
for i, __ in enumerate(str1):
if i+1 < len(str1) and i % 2 == 0 or i == 0:
result += str1[i].upper() + str1[i + 1].lower()
I tried to modify as minimal as possible in your code, so that you could understand properly. I just added a for loop with step 2 so that you wouldn't end up with index out of range. And for the final character in case of odd length string, I handled separately.
def skyline (str1):
result = ''
length = len(str1)
for index in range(0, length - 1, 2):
result += str1[index].upper() + str1[index + 1].lower()
if length % 2 == 1:
result += str1[length - 1].upper()
return result
You can use the following code:
def myfunc(str1):
result=''
for i in range(0,len(str1)):
if i % 2 == 0:
result += str1[i].upper()
else:
result += str1[i].lower()
return result
in your code you are get 2 word by one time so you should divide your loop by 2 because your loop work by depending your input string so make an variable like peak and equal it to len(your input input) then peak = int(peak/2) it will solve your pr
def func(name):
counter1 = 0
counter2 = 1
string = ''
peak = len(name)
peak = int(peak/2)
for letter in range(1,peak+1):
string += name[counter1].lower() + name[counter2].upper()
counter1 +=2
counter2 +=2
return string

Sum a list of numbers until a number X is found

In my program I need to put a while function which sums this list until a particular number is found:
[5,8,1,999,7,5]
The output is supposed to be 14, because it sums 5+8+1 and stops when it finds 999.
My idea looks like:
def mentre(llista):
while llista != 999:
solution = sum(llista)
return solution
Use the iter-function:
>>> l = [5,8,1,999,7,5]
>>> sum(iter(iter(l).next, 999))
14
iter calls the first argument, until the second argument is found. So all numbers are summed up, till 999 is found.
Since you mention using a while loop, you could try a generator-based approach using itertools.takewhile:
>>> from itertools import takewhile
>>> l = [5,8,1,999,7,5]
>>> sum(takewhile(lambda a: a != 999, l))
14
The generator consumes from the list l as long as the predicate (a != 999) is true, and these values are summed. The predicate can be anything you like here (like a normal while loop), e.g. you could sum the list while the values are less than 500.
An example of explicitly using a while loop would be as follows:
def sum_until_found(lst, num):
index = 0
res = 0
if num in lst:
while index < lst.index(num):
res += lst[index]
index += 1
else:
return "The number is not in the list!"
return res
Another possible way is:
def sum_until_found(lst, num):
index = 0
res = 0
found = False
if num in lst:
while not found:
res += lst[index]
index += 1
if lst[index] == num:
found = True
else:
return "The number is not in the list!"
return res
There's many ways of doing this without using a while loop, one of which is using recursion:
def sum_until_found_3(lst, num, res=0):
if num in lst:
if lst[0] == num:
return res
else:
return sum_until_found_3(lst[1:], num, res + lst[0])
else:
return "The number is not in the list!"
Finally, an even simpler solution:
def sum_until_found(lst, num):
if num in lst:
return sum(lst[:lst.index(num)])
else:
return "The number is not in the list!"
Use index and slice
def mentre(llista):
solution = sum(lista[:lista.index(999)])
return solution
Demo
>>> lista = [5,8,1,999,7,5]
>>> sum(lista[:lista.index(999)])
14

Categories