How to find char in string and get all the indexes?
PythonStringPython Problem Overview
I got some simple code:
def find(str, ch):
for ltr in str:
if ltr == ch:
return str.index(ltr)
find("ooottat", "o")
The function only return the first index. If I change return to print, it will print 0 0 0. Why is this and is there any way to get 0 1 2
?
Python Solutions
Solution 1 - Python
This is because str.index(ch)
will return the index where ch
occurs the first time. Try:
def find(s, ch):
return [i for i, ltr in enumerate(s) if ltr == ch]
This will return a list of all indexes you need.
P.S. Hugh's answer shows a generator function (it makes a difference if the list of indexes can get large). This function can also be adjusted by changing []
to ()
.
Solution 2 - Python
I would go with Lev, but it's worth pointing out that if you end up with more complex searches that using re.finditer may be worth bearing in mind (but re's often cause more trouble than worth - but sometimes handy to know)
test = "ooottat"
[ (i.start(), i.end()) for i in re.finditer('o', test)]
# [(0, 1), (1, 2), (2, 3)]
[ (i.start(), i.end()) for i in re.finditer('o+', test)]
# [(0, 3)]
Solution 3 - Python
Lev's answer is the one I'd use, however here's something based on your original code:
def find(str, ch):
for i, ltr in enumerate(str):
if ltr == ch:
yield i
>>> list(find("ooottat", "o"))
[0, 1, 2]
Solution 4 - Python
def find_offsets(haystack, needle):
"""
Find the start of all (possibly-overlapping) instances of needle in haystack
"""
offs = -1
while True:
offs = haystack.find(needle, offs+1)
if offs == -1:
break
else:
yield offs
for offs in find_offsets("ooottat", "o"):
print offs
results in
0
1
2
Solution 5 - Python
def find_idx(str, ch):
yield [i for i, c in enumerate(str) if c == ch]
for idx in find_idx('babak karchini is a beginner in python ', 'i'):
print(idx)
output:
[11, 13, 15, 23, 29]
Solution 6 - Python
Get all the position in just one line
word = 'Hello'
to_find = 'l'
# in one line
print([i for i, x in enumerate(word) if x == to_find])
Solution 7 - Python
As the rule of thumb, NumPy arrays often outperform other solutions while working with POD, Plain Old Data. A string is an example of POD and a character too. To find all the indices of only one char in a string, NumPy ndarrays may be the fastest way:
def find1(str, ch):
# 0.100 seconds for 1MB str
npbuf = np.frombuffer(str, dtype=np.uint8) # Reinterpret str as a char buffer
return np.where(npbuf == ord(ch)) # Find indices with numpy
def find2(str, ch):
# 0.920 seconds for 1MB str
return [i for i, c in enumerate(str) if c == ch] # Find indices with python
Solution 8 - Python
x = "abcdabcdabcd"
print(x)
l = -1
while True:
l = x.find("a", l+1)
if l == -1:
break
print(l)
Solution 9 - Python
This is slightly modified version of Mark Ransom's answer that works if ch
could be more than one character in length.
def find(term, ch):
"""Find all places with ch in str
"""
for i in range(len(term)):
if term[i:i + len(ch)] == ch:
yield i
Solution 10 - Python
All the other answers have two main flaws:
- They do a Python loop through the string, which is horrifically slow, or
- They use numpy which is a pretty big additional dependency.
def findall(haystack, needle):
idx = -1
while True:
idx = haystack.find(needle, idx+1)
if idx == -1:
break
yield idx
This iterates through haystack
looking for needle
, always starting at where the previous iteration ended. It uses the builtin str.find
which is much faster than iterating through haystack
character-by-character. It doesn't require any new imports.
Solution 11 - Python
To embellish the five-star one-liner posted by @Lev and @Darkstar:
word = 'Hello'
to_find = 'l'
print(", ".join([str(i) for i, x in enumerate(word) if x == to_find]))
This just makes the separation of index numbers more obvious.
Result will be: 2, 3
Solution 12 - Python
You could try this
def find(ch,string1):
for i in range(len(string1)):
if ch == string1[i]:
pos.append(i)