How to compare individual characters in two strings in Python 3 [duplicate] - python

This question already has answers here:
How do I iterate through two lists in parallel?
(8 answers)
Closed 5 months ago.
I'm trying to compare the first character of two different strings (and so on) to form a new string based on those results. This is what I've tried using, however its comparing every element of each list to each other.
def compare(a,b):
s = ""
for x in a:
for y in b:
if x == y:
s+=str(x)
else:
s+=str(y)
It seems like such a simple question but I'm stuck.

Use zip:
def compare(a, b):
for x, y in zip(a, b):
if x == y:
...

Are you perhaps looking for something with logic similar to this? It chooses the alphabetically earlier character from each input string:
def compare(a,b):
s = ""
for i in range(len(a)):
if a[i] < b[i]:
s+=str(a[i])
else:
s+=str(b[i])
return s
print compare ("seven", "eight")
Output:
eegen
The one-line version of this is
return ''.join(a[i] if a[i] < b[i] else b[i] for i in range(len(a)))

input(x)
input(y)
cnt = 0
for char_val in x:
if b[cnt] == char_val:
print("match")
else:
print("mis-match")

Here is a complete function
def compare_strings(a,b):
result = True
if len(a) != len(b): print('string lengths do not match!')
for i,(x,y) in enumerate(zip(a,b)):
if x != y:
print(f'char miss-match {x,y} in element {i}')
result = False
if result: print('strings match!')
return result

def twoStrings(s1, s2):
for i in range(len(s1)):
for j in range(len(s2)):
if s2[j] == s1[i]:
return 'YES'
return 'NO'

We can write simple and easy method to compare similar letters in two strings
def compare(a,b):
s = ""
t=""
for x in a:
for y in b:
if x == y:
t=x
s=s+t
print(s)
compare("xyz","axy")
Here first for loop will compare each letters in string and display all similar character.

Related

Summation of values in nested lists

I have encountered a problem where a return gives None back, though the variable had a value just a single line of code before.
mylist = [[7]]
def sumcalc(the_list,n):
s = n
for x,y in enumerate(the_list):
if type(y) == list:
sumcalc(y,s)
elif type(y) == int:
s += y
if x < len(the_list)-1:
sumcalc(the_list[x+1], s)
else:
print (s)
return s
print(sumcalc(mylist,0))
The print command in the second to last line gives me 7, as expected. But the return is None. Any help on this would be appreciated :)
If you are writing a recursive function. You must put return key word before recursive call.
mylist = [[7]]
def sumcalc(the_list,n):
s = n
for x,y in enumerate(the_list):
if type(y) == list:
return sumcalc(y,s)
elif type(y) == int:
s += y
if x < len(the_list)-1:
sumcalc(the_list[x+1], s)
else:
print (s)
return s
print(sumcalc(mylist,0))
sumcalc() doesn't do anything on its own; you need to use the return value. Beyond this, the index checking is unecessary, as the return could simply be placed after the loop. Here is a simpler way of writing the nested sum code.
def nested_sum(x):
if type(x)==int:
return x
if type(x)==list:
return sum(
nested_sum(item)
for item in x
)

Python: check if a list can be sorted by swapping two elements, only one swap is allowed

Here in below code, I'm trying to find out if there are two elements in left side which are greater than right side element but this doesn't seem to work for my problem. Any hints to write further logic? I'm stuck here.
swap.py
def swap(lst):
count = 0
for k in range(0, len(lst)-1):
if lst[k] > lst[k+1]:
count += 1
if int(count) == 2:
print "Swapped"
elif int(count) == 0:
print True
else:
print False
if __name__ == "__main__":
swap([1,2,3,4,0])
swap([6,4,2,5])
swap([6,4,2,8])
swap([1,4,5])
My expected output from program -
[1,4,5] will return True
[6,4,2,8] will return Swapped
[6,4,2,5] will return False
from itertools import combinations
def is_swappable(lst):
s = sorted(lst)
for i, j in combinations(range(len(lst)), 2):
l = lst[:]
l[i], l[j] = l[j], l[i]
if l == s:
return True
return False
Here's a pretty naive solution. Tries swapping every pair in the list and sees if that results in the sorted list.
I did not understand the "swapped" condition but the following code snipped will tell you if you can sort an array in one swap or not.
Code is written in Python 3 and the complexity of this code is O(nlog(n))
def checkOneSwap(arr):
N = len(arr)
if N <= 2:
print(True)
arr2 = []
for index in range(N):
arr2.append(arr[index])
arr2.sort()
counter = 0
for i in range(N):
if arr[i] != arr2[i]:
counter += 1
if counter == 0 or counter == 2:
print(True)
else:
print(False)
checkOneSwap([1,2,3,4,0]) # False you definetly need for than 2 swap to make this array sorted
checkOneSwap([6,4,2,5]) # False [2,4,5,6] -> swap(6,2) and then swap(6,5) require 2 swap to make this array sorted
checkOneSwap([6,4,2,8]) # True [2,4,6,8] -> swap(6,2), one swap required to make this array sorted
checkOneSwap([1,4,5]) # True [1,4,5] -> already sorted,counter = 0
Can be done with for loop, but I prefer list comprehension. Zip sorted and unsorted list and create a list of mismatches. If the length of mismatches is more than 2, then you can't sort in 1 swap.
def is_sortable_by_one_swap(unsorted_list):
mismatches = [x for x in zip(unsorted_list, sorted(unsorted_list)) if x[0] != x[1]]
return len(mismatches) <= 2

Combine two strings (char by char) and repeat last char of shortest one

I have two strings, (string1 and string2).
If they are equal in length, the function should return a string that is formed by alternating characters from each of the two strings.
If they are not equal in length, then the function extends the shorter string by repeating the last character until they are the same length and then alternates the characters of the two strings.
For example,
extendedString("abc", "def") => "adbecf"
extendedString("ab", "defg") => "adbebfbg"
I have written the part where it returns if the strings are the same length, but I have no idea how to repeat the last character.
def extendedString(string1, string2):
x = string1
y = string2
z = ""
if len(x) == len(y):
return "".join(i for j in zip(string1,string2) for i in j)
You can use the zip_longest function from itertools.
Works like zip, but gives you the ability to fill the blanks (default filler is None, but you can change it:
import itertools
def extendedString(string1,string2):
filler = string2[-1] if len(string1)>len(string2) else string1[-1]
return "".join(i for j in itertools.zip_longest(string1, string2, fillvalue=filler) for i in j)
update
added the filler to be the last char of the shortest string (in case it's needed)
In [50]: extendedString("abc","def")
Out[50]: 'adbecf'
In [51]: extendedString("ab","defg")
Out[51]: 'adbebfbg'
If you are using python2 the function is itertools.izip_longest
A one-liner solution that doesn't require itertools:
def extendedString(a,b):
return ''.join(x+y for x,y in zip(*(s+s[-1]*(max(len(a),len(b))-len(s)) for s in (a,b))))
Output:
$ extendedString('abc','1234')
'a1b2c3c4'
$ extendedString('abc','12')
'a1b2c2'
First make both the strings of same length and then join. Something like:
def extendedString(string1,string2):
x=string1
y=string2
if len(x) < len(y):
x = x + x[-1] * (len(y) - len(x))
elif len(x) > len(y):
y = y + y[-1] * (len(x) - len(y))
return "".join(i for j in zip(x, y) for i in j)
print extendedString("abc", "def")
print extendedString("ab","defg")
print extendedString("defg","ab")
Output:
$ python test.py
adbecf
adbebfbg
daebfbgb
$
Simply add the last character to the shorter string until their length is same. In python, string*int is defined. For example "a"*3 is "aaa". So
x = x+x[-1]*(len(y)-len(x)) does what you need to do. Then you just need to recursively call the function with the new string values that have the same length.
def extendedString(string1,string2):
x=string1
y=string2
z=""
if len(x)==len(y):
return "".join(i for j in zip(string1,string2) for i in j)
elif len(x) < len(y):
x = x+x[-1]*(len(y)-len(x))
return extendedString(x,y)
else:
y = y+y[-1]*(len(x)-len(y))
return extendedString(x,y)
You can accomplish the case where the length is not equal by finding the shorter and the longer of the strings, and appending N of the -1th character of the shorter string to itself, where N is the difference in length between the shorter and longer. From there, you return the same zip/join expression.
def extendedString(string1, string2):
if len(string1) == len(string2):
return "".join(i for j in zip(string1, string2) for i in j)
else:
longer, shorter = (string1, string2) if len(string1) > len(string2) else (string2, string1)
shorter = shorter + shorter[-1] * (len(longer) - len(shorter))
return "".join(i for j in zip(shorter, longer) for i in j)
a = "hell"
b = "heaven"
print "".join(i for j in itertools.izip_longest(a, b, fillvalue=a[-1] if len(a)<len(b) else b[-1]) for i in j)
Output: hheelalvleln
OK, I realize this has been answered into oblivion, but I had already started working on mine, so here it goes.
Note: this implementation will always start printing the shorter string first, if you want to always start off by printing the first char of string1, then see my update below.
I like that you copy the input parameters as that is a good habit for preserving input, and I just modified it slightly to add a convention so len(x) <= len(y) is always true. I also opted to not use other libraries but to implement the zip myself.
def extendedString(string1, string2):
if len(string1) <= len(string2): # Convention: len(x) <= len(y)
x = string1
y = string2
else:
x = string2
y = string1
z=""
for i in range(len(x)): # Go through shorter string
z+=x[i] # Add the i-th char in x to z
z+=y[i] # Add the i-th char in y to z
if i < len(y): # If the second string is longer
for j in range(i+1, len(y)): # for the rest of the length
z+=x[i] # add the last char of x to z
z+=y[j] # add the j-th char of y to z
return z
print(extendedString("abc", "efg"))
print(extendedString("ab", "defg"))
print(extendedString("abcd", "ef"))
Output:
$ python zip.py
aebfcg
adbebfbg
eafbfcfd
Update
This implementation will ensure that string1 is always printed first.
def extendedString(string1, string2):
x = string1
y = string2
z=""
if len(x) <= len(y):
shorter = x
longer = y
else:
shorter = y
longer = x
for i in range(len(shorter)):
z+=x[i]
z+=y[i]
if i < len(longer):
for j in range(i+1, len(longer)):
if shorter == x:
z+=x[i]
z+=y[j]
else:
z+=x[j]
z+=y[i]
return z
print(extendedString("abc", "efg"))
print(extendedString("ab", "defg"))
print(extendedString("abcd", "ef"))
Output:
$ python zip.py
aebfcg
adbebfbg
aebfcfdf

How to add a counter to a recursive function? [Python]

The program has to replace two numbers within the list with a number that is also given in the parameters. I can't change the parameters, but I can create other functions also. In addition I must use recursion. So far I figured out how to do the replacement with recursion, but I'm confused about the count. Every time I try I cant seem to only replace the first two occurrences of 'x' with 'y', instead I always get to replace every 'x' with 'y'.
EDIT: And I can't use global variables.
def replaceFirstTwo(x,y,lst):
if lst == []:
return []
else:
if lst[0] == x:
return [y] + replaceFirstTwo(x,y,lst[1:])
else:
return [lst[0]]+ replaceFirstTwo(x,y,lst[1:])
A correct outcome should look like this :
replaceFirstTwo(1,2,[5,1,2,3,1,1])
[5, 2, 2, 3, 2, 1]
If x is only ever going to be positive then you can use, the negative version to signify that it is the second time that you are running the function. Before changing x to something to signify do nothing.
I have modified your function so it does this, however it will not work with negative values of x as the abs(x) will make it positive.
def replaceFirstTwo(x,y,lst):
if lst == []:
return []
else:
if x is not None:
if lst[0] == abs(x):
if x > -1:
x = -x
else:
x = None
return [y] + replaceFirstTwo(x,y,lst[1:])
else:
return [lst[0]]+ replaceFirstTwo(x,y,lst[1:])
else:
return [lst[0]]+ replaceFirstTwo(x,y,lst[1:])
Here's an alternative using an inner function, which has no restrictions such as the accepted solution:
def replaceFirstTwo(x, y, lst):
def sub(lst, res, count):
if lst:
e = lst[0]
if e == x and count < 2:
return sub(lst[1:], res+[y], count + 1)
else:
return sub(lst[1:], res+[e], count)
else:
return res
return sub(lst, [], 0)

Python: Most efficient way to compare two lists of integers

I'm trying to compare two lists of integers, each the same size, in Python 2.6. The comparison I need is to compare the first item in List 1 with the first item in List 2, the second item in List 1 with the second item in List 2, and so on, and returns a result if ALL of the list items follow the same comparison criteria. It should behave as follows:
list1 = [1,1,1,1]
list2 = [2,1,2,3]
compare(list1,list2)
# returns a "list 1 is <= list 2" response.
list1 = [4,1,4,3]
list2 = [2,1,2,3]
compare(list1,list2)
# returns a "list 1 is >= list 2" response.
list1 = [3,2,3,2]
list2 = [1,4,1,4]
compare(list1,list2)
# returns None— some items in list1 > list2, and some items in list2 > list1.
I figured I could write the code like the following block, but I don't know if it's the most efficient. My program is going to be calling this method a LOT so I want to streamline this as much as possible.
def compare(list1,list2):
gt_found = 0
lt_found = 0
for x in range(len(list1)):
if list1[x] > list2[x]:
gt_found += 1
elif list1[x] < list2[x]:
lt_found += 1
if gt_found > 0 and lt_found > 0:
return None #(some items >, some items <)
if gt_found > 0:
return 1 #(list1 >= list2)
if lt_found > 0:
return -1 #(list1 <= list2)
return 0 #(list1 == list2)
Is it already as good as it's going to get (big-O of n), or is there a faster way to go about it (or a way that uses system functions instead)?
CLARIFICATION: I expect the case that returns 'None' to happen the most often, so it is important.
You can consider a numpy-based vectorized comparison.
import numpy as np
a = [1,1,1,2]
b = [2,2,4,3]
all_larger = np.all(np.asarray(b) > np.asarray(a)) # true if b > a holds elementwise
print all_larger
True
Clearly, you can engineer the thing to have your answer.
all_larger = lambda b,a : np.all(np.asarray(b) > np.asarray(a))
if all_larger(b,a):
print "b > a"
elif all_larger(a,b):
print "a > b"
else
print "nothing!"
Every type of comparison such as <, >, <=, >=, can be done.
Are you familiar with the wonderful zip function?
import itertools
def compare(xs, ys):
all_less = True
all_greater = True
for x, y in itertools.izip(xs, ys):
if not all_less and not all_greater:
return None
if x > y:
all_less = False
elif x < y:
all_greater = False
if all_less:
return "list 1 is <= list 2"
elif all_greater:
return "list 1 is >= list 2"
return None # all_greater might be set False on final iteration
Zip takes two lists (xs and ys in this case, but call them whatever you want) and creates an iterator for a sequence of tuples.
izip([1,2,3,4], [4,3,2,1]) == [(1,4), (2,3), (3,2), (4,1)]
This way you can iterate through both lists simultaneously and compare each value in tandem. The time complexity should be O(n), where n is the size of your lists.
It will return early in cases where neither the >= or <= condition are met.
Update
As James Matta points out, itertools.izip performs better than the standard zip in Python 2. This isn't true in Python 3, where the standard zip works the way izip does in older versions.
For anyone interested in the performance of the two methods, I named the iterative method 'tortoise' and the numpy method 'hare', and tested it with the code below.
At first, the 'tortoise' won [.009s [T] vs .033s [H]], but I checked it and found that asarray() was being called more often than it need to be. With that fix, the 'hare' won again, [.009s [T] vs .006s [H]].
The data is here: http://tny.cz/64d6e5dc
It consists of 28 lines of about 950 elements in length. Four of the lines collectively >= all the others.
It might be interesting to see how the performance works on larger data sets.
import itertools, operator, math
import cProfile
import numpy as np
data = #SEE PASTEBIN
def tortoise(xs, ys):
all_less = True
all_greater = True
for x, y in zip(xs, ys):
if not all_less and not all_greater:
return None
if x > y:
all_less = False
elif x < y:
all_greater = False
if all_greater and all_less:
return 0
if all_greater:
return 1
if all_less:
return -1
return None # all_greater might be set False on final iteration
hare = lambda b,a : np.all(b >= a)
def find_uniques_tortoise():
include_list = range(len(data))
current_list_index = 0
while current_list_index < len(data):
if current_list_index not in include_list:
current_list_index += 1
continue
for x in range(current_list_index+1,len(data)):
if x not in include_list:
continue
result = tortoise(data[current_list_index], data[x])
if result is None: #no comparison
continue
elif result == 1 or result == 0: # this one beats the other one
include_list.remove(x)
continue
elif result == -1: #the other one beats this one
include_list.remove(current_list_index)
break
current_list_index +=1
return include_list
def find_uniques_hare():
include_list = range(len(data))
current_list_index = 0
#do all asarray()s beforehand for max efficiency
for x in range(len(data)):
data[x] = np.asarray(data[x])
while current_list_index < len(data):
if current_list_index not in include_list:
current_list_index += 1
continue
for x in range(current_list_index+1,len(data)):
if x not in include_list:
continue
if hare(data[current_list_index], data[x]): # this one beats the other one, or it's a tie
include_list.remove(x)
# print x
continue
elif hare(data[x], data[current_list_index]): #the other one beats this one
include_list.remove(current_list_index)
# print current_list_index
break
else: #no comparison
continue
current_list_index +=1
return include_list
cProfile.run('find_uniques_tortoise()')
cProfile.run('find_uniques_hare()')
print find_uniques_tortoise()
print
print find_uniques_hare()

Categories

Resources