Finding the Index of the First Occurrence of Any Item in a List

Finding first and last index of some value in a list in Python

Sequences have a method index(value) which returns index of first occurrence - in your case this would be verts.index(value).

You can run it on verts[::-1] to find out the last index. Here, this would be len(verts) - 1 - verts[::-1].index(value)

Get indexes for first occurrence of each element in a list?

I think you just want to use enumerate (unless you want the first occurrence of each item in the list):

strings = ["foo", "bar", "baz", "bar", "foo"]
for index, value in enumerate(strings):
print index, value

outputs

0 foo
1 bar
2 baz
3 bar
4 foo

If you wanted, for example, 1 bar instead of 3 bar, you can maintain a dictionary of found strings:

for index, value in enumerate(strings):
if value not in d:
d[value] = index

for value in strings:
print value, d[value]

Python - find index position of first occurrence of a list of strings within a string

Following along with your example's logic, this jumped out as the most expedient method of finding the "first" matching arrow and printing it's location. However, the order of sets are not FIFO, so if you want to preserve order I would suggest substituting a list instead of a set for arrowlist so that the order can be preserved.

    arrowlist = {"->x","->", "->>", "-\\", "\\-","//--","->o","o\\--","<->","<->o"}
def cxn(line, arrowlist):
try:
result = tuple((x, line.find(x)) for x in arrowlist if x in line)[0]
print("found an arrow {} at position {} with length {}".format(result[0], result[1], len(result[0])))

# Remember in general it's not a great idea to use an exception as
# broad as Exception, this is just for example purposes.
except Exception:
return 0

If you're looking for the first match in the provided string (line), you can do that like this:

arrowlist = {"->x","->", "->>", "-\\", "\\-","//--","->o","o\\--","<->","<->o"}

def cxn(line, arrowlist):
try:
# key first sorts on the position in string then shortest length
# to account for multiple arrow matches (i.e. -> and ->x)
result = sorted([(x, line.find(x)) for x in arrowlist if x in line], key=lambda r: (r[1],len(r[0])))[0]
# if you would like to match the "most complete" (i.e. longest-length) word first use:
# result = sorted([(x, line.find(x)) for x in arrowlist if x in line], key=lambda r: (r[1], -len(r[0])))[0]
print("found an arrow {} at position {} with length {}".format(result[0], result[1], len(result[0])))

except Exception:
return 0

Or, if you have access to the standard library you can use operator.itemgetter to almost the same effect and gain efficiency from less function calls:

from operator import itemgetter

arrowlist = {"->x","->", "->>", "-\\", "\\-","//--","->o","o\\--","<->","<->o"}

def cxn(line, arrowlist):
try:
# key first sorts on the position in string then alphanumerically
# on the arrow match (i.e. -> and ->x matched in same position
# will return -> because when sorted alphanumerically it is first)
result = sorted([(x, line.find(x)) for x in arrowlist if x in line], key=(itemgetter(1,0)))[0]
print("found an arrow {} at position {} with length {}".format(result[0], result[1], len(result[0])))

except Exception:
return 0

***NOTE: I am using a slightly different arrowlist than your example just because the one you provided seems to be messing with the default code formatting (likely because of quote closure issues). Remember you can prepend a string with 'r' like this: r"Text that can use special symbols like the escape \and\ be read in as a 'raw' string literal\". See this question for more information about raw string literals.

Finding the index of an item in a list

>>> ["foo", "bar", "baz"].index("bar")
1

Reference: Data Structures > More on Lists

Caveats follow

Note that while this is perhaps the cleanest way to answer the question as asked, index is a rather weak component of the list API, and I can't remember the last time I used it in anger. It's been pointed out to me in the comments that because this answer is heavily referenced, it should be made more complete. Some caveats about list.index follow. It is probably worth initially taking a look at the documentation for it:

list.index(x[, start[, end]])

Return zero-based index in the list of the first item whose value is equal to x. Raises a ValueError if there is no such item.

The optional arguments start and end are interpreted as in the slice notation and are used to limit the search to a particular subsequence of the list. The returned index is computed relative to the beginning of the full sequence rather than the start argument.

Linear time-complexity in list length

An index call checks every element of the list in order, until it finds a match. If your list is long, and you don't know roughly where in the list it occurs, this search could become a bottleneck. In that case, you should consider a different data structure. Note that if you know roughly where to find the match, you can give index a hint. For instance, in this snippet, l.index(999_999, 999_990, 1_000_000) is roughly five orders of magnitude faster than straight l.index(999_999), because the former only has to search 10 entries, while the latter searches a million:

>>> import timeit
>>> timeit.timeit('l.index(999_999)', setup='l = list(range(0, 1_000_000))', number=1000)
9.356267921015387
>>> timeit.timeit('l.index(999_999, 999_990, 1_000_000)', setup='l = list(range(0, 1_000_000))', number=1000)
0.0004404920036904514

Only returns the index of the first match to its argument

A call to index searches through the list in order until it finds a match, and stops there. If you expect to need indices of more matches, you should use a list comprehension, or generator expression.

>>> [1, 1].index(1)
0
>>> [i for i, e in enumerate([1, 2, 1]) if e == 1]
[0, 2]
>>> g = (i for i, e in enumerate([1, 2, 1]) if e == 1)
>>> next(g)
0
>>> next(g)
2

Most places where I once would have used index, I now use a list comprehension or generator expression because they're more generalizable. So if you're considering reaching for index, take a look at these excellent Python features.

Throws if element not present in list

A call to index results in a ValueError if the item's not present.

>>> [1, 1].index(2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: 2 is not in list

If the item might not be present in the list, you should either

  1. Check for it first with item in my_list (clean, readable approach), or
  2. Wrap the index call in a try/except block which catches ValueError (probably faster, at least when the list to search is long, and the item is usually present.)

Search over a list and return the index at first occurrence then assign - 1 if value not there

def find(my_list, value):
index = 0;
for element in my_list:
if element == value:
return index
index += 1
return -1

Python: Find index of the first occurrence of x and then the index of the second occurrence of x

Use list's index() function, where the first argument is the element you are trying to find and the second argument is the index to start from. Maybe something like this:

a = [1, 2, 3, 1, 4, 5, 6, 1, 5]

first_ind_of_one = a.index(1, 0)
second_ind_of_one = a.index(1, first_ind_of_one+1)

print(first_ind_of_one)
print(second_ind_of_one)

Code below for case when we don't know if and how many occurrences of element in list:

occurrences_needed = 2
list_of_inds = []
for ind, elem in enumerate(a):
if len(list_of_inds) == occurrences_needed:
break
if elem == 1:
list_of_inds.append(ind)

print(list_of_inds)

Just for fun, I have added a third method that is easier to read but may be inefficient for large lists (some testing may be required):

s = ''.join(str(i) for i in a)
first_ind = s.find('1')
second_ind = s.find('1', first_ind + 1)
print(first_ind)
print(second_ind)

This converts the list to a string and use's string's find() method. This method simply returns -1 in the event where the element is not found. So you may have to check for that in your code.

Find index to first occurrence of the largest number

def max_number_index(input_list):
idx = 0
max_number = input_list[0]
for i in range(1, len(input_list)):
if input_list[i] > max_number:
max_number = input_list[i]
idx = i
return idx

print(max_number_index([0,1,2,3,4]))
print(max_number_index([-2,34,-43,0,5,9]))
print(max_number_index([2,3,3,3,3]))

4
1
1

You can, of course, use for i in range(len(input_list)): but I thought it unnecessary to follow the instructions exactly to the letter. In that case you look twice at the first item in the list, once to set initial values and then again in the loop.

Find index of first occurrence in sorted list

Your logic is wrong, you have a so called sorted list of strings which unless you compared as integer would not be sorted correctly, you should use integers from the get-go and bisect_left to find index:

from bisect import bisect_left

sortedlist = sorted(map(int, ['0', '0', '0', '1', '1', '1', '2', '2', '3']))

count = 0

def get_val(lst, cn):
if lst[-1] < cn:
return "whatever"
return bisect_left(lst, cn, hi=len(lst) - 1)

If the value falls between two as per your requirement, you will get the first index of the higher value, if you get an exact match you will get that index:

In [13]: lst = [0,0,2,2]

In [14]: get_val(lst, 1)
Out[14]: 2

In [15]: lst = [0,0,1,1,2,2,2,3]

In [16]: get_val(lst, 2)
Out[16]: 4

In [17]: get_val(lst, 9)
Out[17]: 'whatever'

Find first occurrence index value in efficent way in kotlin

If you would like to stick to functional style then you can do it like this:

val result = list.asSequence()
.flatMapIndexed { outer, abc ->
abc.value.asSequence()
.mapIndexed { inner, xyz -> Triple(outer, inner, xyz) }
}
.find { it.third?.isRead == false }

if (result != null) {
val (outer, inner) = result
println("Outer: $outer, inner: $inner")
}

For each ABC item we remember its index as outer and we map/transform a list of its XYZ items into a list of tuples: (outer, inner, xyz). Then flatMap merges all such lists (we have one list per ABC item) into a single, flat list of (outer, inner, xyz).

In other words, the whole flatMapIndexed() block changes this (pseudo-code):

[ABC([xyz1, xyz2]), ABC([xyz3, xyz4, xyz5])]

Into this:

[
(0, 0, xyz1),
(0, 1, xyz2),
(1, 0, xyz3),
(1, 1, xyz4),
(1, 2, xyz5),
]

Then we use find() to search for a specific xyz item and we acquire outer and inner attached to it.

asSequence() in both places changes the way how it works internally. Sequences are lazy, meaning that they perform calculations only on demand and they try to work on a single item before going to another one. Without asSequence() we would first create a full list of all xyz items as in the example above. Then, if xyz2 would be the one we searched, that would mean we wasted time on processing xyz3, xyz4 and xyz5, because we are not interested in them.

With asSequence() we never really create this flat list, but rather perform all operations per-item. find() asks for next item to check, mapIndexed maps only a single item, flatMapIndexed also maps only this single item and if find() succeed, the rest of items are not processed.

In most cases using sequences here could greatly improve the performance. In some cases, like for example when lists are small, sequences may degrade the performance by adding an overhead. However, the difference is very small, so it is better to leave it as it is.

As we can see, functional style may be pretty complicated in cases like this. It may be a better idea to use imperative style and good old loops:

list.indicesOfFirstXyzOrNull { it?.isRead == false }

inline fun Iterable<ABC>.indicesOfFirstXyzOrNull(predicate: (XYZ?) -> Boolean): Pair<Int, Int>? {
forEachIndexed { outer, abc ->
abc.value.forEachIndexed { inner, xyz ->
if (predicate(xyz)) {
return outer to inner
}
}
}

return null
}


Related Topics



Leave a reply



Submit