29

Given:

x = ['w', 'e', 's', 's', 's', 'z','z', 's']

Each occurrence of s appears at the following indices:

1st: 2
2nd: 3
3rd: 4
4th: 7

If I do x.index('s') I will get the 1st index.

How do I get the index of the 4th s?

falsetru
  • 357,413
  • 63
  • 732
  • 636
Rimoun
  • 455
  • 1
  • 9
  • 16
  • 1
    probably duplicate of http://stackoverflow.com/questions/1883980/find-the-nth-occurrence-of-substring-in-a-string – Pavan Gupta Mar 08 '14 at 09:00

7 Answers7

31

Using list comprehension and enumerate:

>>> x = [ 'w', 'e', 's', 's', 's', 'z','z', 's']
>>> [i for i, n in enumerate(x) if n == 's'][0]
2
>>> [i for i, n in enumerate(x) if n == 's'][1]
3
>>> [i for i, n in enumerate(x) if n == 's'][2]
4
>>> [i for i, n in enumerate(x) if n == 's'][3]
7
falsetru
  • 357,413
  • 63
  • 732
  • 636
11

If you didn't want to store the indices for each occurrence, or wanted to work with arbitrary iterables then something like:

from itertools import islice

def nth_index(iterable, value, n):
    matches = (idx for idx, val in enumerate(iterable) if val == value)
    return next(islice(matches, n-1, n), None)

x = [ 'w', 'e', 's', 's', 's', 'z','z', 's']
idx = nth_index(x, 's', 4)
# 7

Note there's a default value of None there in the next. You may wish to change that to something else, or remove it and catch the StopIteration and raise as another more suitable exception (ValueError for instance, so that it ties up more with list.index behaviour).

Jon Clements
  • 138,671
  • 33
  • 247
  • 280
4

For getting the index of the items:

return [index for index, char in enumerate(x) if char == 's']

For getting the character itself:

return [char for index, char in enumerate(x) if char == 's']

Or to get tuples of character/index pairs: (Thanks to falsetru for pointing out a simpler solution)

pairs = [(index, char) for index, char in enumerate(x) if char == 's']
samrap
  • 5,595
  • 5
  • 31
  • 56
  • `enumerate` yields `index-element` pairs, not `element-index` pairs. And `[char, index for ...]` causes a SytnaxError. – falsetru Mar 08 '14 at 09:00
  • oops my bad, let me fix that – samrap Mar 08 '14 at 09:02
  • The last code can be replaced with `pairs = [(index, char) for index, char in enumerate(x) if char == 's']` or `pairs = [pair for pair in enumerate(x) if pair[1] == 's']`. – falsetru Mar 08 '14 at 09:08
1
def find_nth_character(str1, substr, n):
    """find the index of the nth substr in string str1""" 
    k = 0
    for index, c in enumerate(str1):
        #print index, c, n  # test
        if c == substr:
            k += 1
            if k == n:
                return index


str1 = "B.765.A87_43.Left.9878.xx8"
substr = '.'
occurance = 4

print "%s #%d at index %d" % (substr, occurance, find_nth_character(str1, substr, occurance))
Pavan Gupta
  • 17,663
  • 4
  • 22
  • 29
0

Here is a more Pythonic approach using itertools.count and a generator expression:

In [24]: def get_nth_index(lst, item, n):
    ...:     c = count()
    ...:     return next(i for i, j in enumerate(x) if j=='s' and next(c) == n-1)

Demo:

In [25]: get_nth_index(x, 's', 2)
Out[25]: 3

In [26]: get_nth_index(x, 's', 3)
Out[26]: 4

In [27]: get_nth_index(x, 's', 4)
Out[27]: 7

In [28]: get_nth_index(x, 's', 5)
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-28-fc4e5e8c31ef> in <module>()
----> 1 get_nth_index(x, 's', 5)

<ipython-input-24-5394f79b3c30> in get_nth_index(lst, item, n)
      1 def get_nth_index(lst, item, n):
      2     c = count()
----> 3     return next(i for i, j in enumerate(x) if j=='s' and next(c) == n-1)

StopIteration: 

In [29]: 

As you can see, it will raise an StopIteration exception in case it can't find a match. You can also pass a default argument to next() function to return a default value instead of raising exception.

Mazdak
  • 105,000
  • 18
  • 159
  • 188
0

simply we can extend the functionality of the built-in list class. by inheriting it.

In [64]: class List(list):
       :     def __init__(self, *val):
       :         self.extend(list(val))
       :
       :
       :     def findidx(self, val, n=None):
       :         '''return the occurances of an object in a list'''
       :
       :         if n == None:
       :             return [i for i, v in enumerate(self) if v == val]
       :
       :         return [i for i, v in enumerate(self) if v == val][n]

and there are two ways to use this class. see in the following example to understand.

In [65]: c = List(4, 5, 6, 7, 2, 5, 4 ,4) # enter the elements of the list as a argument

In [69]: c.findidx(4, 0) # search 4's 0th(1) occurance
Out[69]: 0

In [72]: c.findidx(4, 1) # find 4's 1st(2) occurance
Out[72]: 6

or

In [66]: c.findidx(4) # find all occurances of 4
Out[66]: [0, 6, 7]

In [67]: c.findidx(4)[0] # first occurance
Out[67]: 0

In [67]: c.findidx(4)[2] # third occurance
Out[67]: 7

In [69]: c[0]# for verification
Out[69]: 4

In [70]: c[7]
Out[70]: 4

`

Anu
  • 21
  • 5
0

You can use this to find in last position

where a is the array

t=(a.index(0)+a.count(0))-1

You can increase the number to -2 or -3 to find the position of the desired number from last

NOTE: The list must be sorted. You can sort it with sort ()

eg: a.sort()

for more inbuilt function in list click here

vk16_dev
  • 11
  • 1