How to find char in string and get all the indexes?

PythonString

Python 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:

  1. They do a Python loop through the string, which is horrifically slow, or
  2. 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)        
    

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionWilliam XingView Question on Stackoverflow
Solution 1 - PythonLev LevitskyView Answer on Stackoverflow
Solution 2 - PythonJon ClementsView Answer on Stackoverflow
Solution 3 - PythonMark RansomView Answer on Stackoverflow
Solution 4 - PythonHugh BothwellView Answer on Stackoverflow
Solution 5 - PythonBabak KarchiniView Answer on Stackoverflow
Solution 6 - PythonDarkstar DreamView Answer on Stackoverflow
Solution 7 - PythonAnton KView Answer on Stackoverflow
Solution 8 - PythonArvind KumarView Answer on Stackoverflow
Solution 9 - PythondashesyView Answer on Stackoverflow
Solution 10 - PythonJonathanView Answer on Stackoverflow
Solution 11 - PythonScripterMikeView Answer on Stackoverflow
Solution 12 - Pythonuser2179861View Answer on Stackoverflow