Reputation: 606
is there a better way to find the first appearance of one of the chars: 'x','y','z' in someStr?
def findFirstAppearance(someStr):
x = someStr.find('x');
y = someStr.find('y');
z = someStr.find('z');
if x == -1: x= len(someStr);
if y == -1: y= len(someStr);
if z == -1: z= len(someStr);
return min(x,y,z);
for example: for someStr = "axby" it should return 1. for someStr = "aybx" it should also return 1.
thanks!
Upvotes: 1
Views: 1901
Reputation: 45542
Here's an alternative using regular expressions.
import re
def find_first_dx(needles, haystack):
match = re.search('|'.join(map(re.escape, needles)), haystack)
return match.start() if match else -1
Examples:
>>> find_first_dx('xyz', 'abcyax')
3
>>> find_first_dx('xyz.', 'a.bcyax')
1
>>> find_first_dx('xyz', 'fee fi foe fum')
-1
>>> find_first_dx(['foe', 'fum'], 'fee fi foe fum')
7
Upvotes: 1
Reputation: 110271
For a lot of chars, you should seriously think about using a regular expression, especially if you are doing this in a loop in your application:
import re
def findall(string, chars)
m = re.search("[%s]" % chars, string, re.DOTALL)
if m:
return m.start()
return -1
this should be at least 100x faster than a pure-python loop with a call to "find" for each char.
Just be aware that if you need to find a char that is used for other purposes inside regexps "[ ]" , you should escape them (like "-", "^")
Upvotes: 0
Reputation: 250941
Use enumerate()
, it yields a tuple for each character of the string.
Tuple's first element is the index and second element is the character itself.
In [103]: def find_first(strs):
.....: for i,x in enumerate(strs):
.....: if x in 'xyz': #if current character is either
#'x' or 'y' or 'z' then return index
.....: return i
.....: return -1 #if the loop completed successfully then return -1
.....:
In [104]: find_first("fooxbaryzx")
Out[104]: 3
In [105]: find_first("qwerty")
Out[105]: 5
In [106]: find_first("qwert")
Out[106]: -1
In [107]: find_first("axby")
Out[107]: 1
In [108]: find_first("aybx")
Out[108]: 1
Upvotes: 0
Reputation: 20126
This should work:
def findany(s1, s2):
for i, x in enumerate(s1):
if x in s2:
return i
return -1
Upvotes: 0
Reputation: 353059
Maybe:
>>> s = 'this string x contains y several letters z'
>>> next(i for i,c in enumerate(s) if c in 'xyz')
12
>>> s[12]
'x'
This will raise an exception if it's not found, which could be fixed by using a default value:
>>> next(i for i,c in enumerate(s) if c in 'Q')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>> next((i for i,c in enumerate(s) if c in 'Q'), -1)
-1
You could also pre-construct a set to test membership in:
>>> special = set("vmp")
>>> next((i for i,c in enumerate(s) if c in special), -1)
27
which might be faster if there were a lot of letters to test against; it'll depend a lot on the sizes involved. Easy to experiment if it matters, but (spoiler alert) it probably doesn't.
Upvotes: 2
Reputation: 10050
I think this is what you're looking for. This finds the first occurance of one of may chars (items
) in a string. It works just like str.find
.
def findany(string, items, start, end=-1):
if end == -1:
end = len(string)
for i in range(start, end):
c = string[i]
if c in items:
return i
return -1
# 01234567
inp = "hellozxy"
print findany(inp, "xyz") # 5 = z
print findany(inp, "?") # -1 = not found
print findany(inp, ["o", "l"], 3) # 3, skips the first 'l'
Note: You pass a list of chars (1-character strings) as items
. In python, a string is just that. If you pass something like ["x", "y", "blah"], it won't work (it'll ignore "blah").
Upvotes: 0