A non-slicky method:
def index_containing_substring(the_list, substring):
for i, s in enumerate(the_list):
if substring in s:
return i
return -1
Answer from kennytm on Stack Overflowpython - Find a substring in a string and returning the index of the substring - Stack Overflow
python - Finding substring in list of strings, return index - Stack Overflow
How do I search a list of Strings for a certain word and return the index?
python - How to find starting index of a string if it contains any element from a list of substrings - Stack Overflow
A non-slicky method:
def index_containing_substring(the_list, substring):
for i, s in enumerate(the_list):
if substring in s:
return i
return -1
With a one-liner:
index = [idx for idx, s in enumerate(l) if 'tiger' in s][0]
There's a builtin method find on string objects.
s = "Happy Birthday"
s2 = "py"
print(s.find(s2))
Python is a "batteries included language" there's code written to do most of what you want already (whatever you want).. unless this is homework :)
find returns -1 if the string cannot be found.
Ideally you would use str.find or str.index like demented hedgehog said. But you said you can't ...
Your problem is your code searches only for the first character of your search string which(the first one) is at index 2.
You are basically saying if char[0] is in s, increment index until ch == char[0] which returned 3 when I tested it but it was still wrong. Here's a way to do it.
def find_str(s, char):
index = 0
if char in s:
c = char[0]
for ch in s:
if ch == c:
if s[index:index+len(char)] == char:
return index
index += 1
return -1
print(find_str("Happy birthday", "py"))
print(find_str("Happy birthday", "rth"))
print(find_str("Happy birthday", "rh"))
It produced the following output:
3
8
-1
I don't think there is a good (i.e. readable) one-line solution for this. Alternatively to @eugene's loop, you could also use a try/except.
def get_index(list_of_strings, substring):
try:
return next(i for i, e in enumerate(list_of_strings) if substring in e)
except StopIteration:
return len(list_of_strings) - 1
The code is a little longer, but IMHO the intent is very clear: Try to get the next index that contains the substring, or the length of the list minus one.
Update: In fact, there is a good (well, somewhat okay-ish) one-liner, and you almost had it, using the default parameter of next, but instead of using the last element itself as default, and then calling index, just put the index itself and combine with enumerate:
next((i for i, e in enumerate(list_of_strings) if substring in e),
len(list_of_strings) - 1)
Using enumerate() in a function would be both more readable and efficient:
def get_index(strings, substr):
for idx, string in enumerate(strings):
if substr in string:
break
return idx
Note that you don't need to call .readlines() on a file object to iterate over the lines โ just use it as an iterable.
For example if I have a list
cities = ["The capital of france is Paris", "The capital of france is Berlin"," The capital of france is London"," The capital of france is Barcelona"]
How do I search the list for "Berlin" and get the index of the sentence containing "Berlin"?
Use a loop:
for item in my_list:
print(s.find(item))
One approach is to search the string for the elements in your list, and return the index of the first match. We exit on the first match found (since you want any element, there's no need to test remaining substrings past that point).
def find_index_first_match(target, *args):
for arg in args:
search = target.find(arg)
# If arg is not in target, search is -1.
if search >= 0:
return search
# You could return -1 here so the return's more
# consistent with str.find's behavior.
return None
find_index_first_match(s, *my_list)
I know it's been a while since this question was active, but here's another solution anyways in case anyone is interested.
Your way seems fine, but here is a similar strategy, using the list.index() method:
starts = [lines.index(l) for l in lines if l.startswith('sub')]
As far as time goes, the two functions clock in at about the same (on average 1.7145156860351563e-06 seconds for your enumerate solution and 1.7133951187133788e-06 seconds for my .index() solution)
While I like your approach, here is another one that handles identical entries in lines correctly (i.e. similar to the way your sample code does), and has comparable performance, also for the case that the length of lines grows:
starts = [i for i in range(len(lines)) if lines[i].startswith('sub')]
print [s for s in list if sub in s]
If you want them separated by newlines:
print "\n".join(s for s in list if sub in s)
Full example, with case insensitivity:
mylist = ['abc123', 'def456', 'ghi789', 'ABC987', 'aBc654']
sub = 'abc'
print "\n".join(s for s in mylist if sub.lower() in s.lower())
All the answers work but they always traverse the whole list. If I understand your question, you only need the first match. So you don't have to consider the rest of the list if you found your first match:
mylist = ['abc123', 'def456', 'ghi789']
sub = 'abc'
next((s for s in mylist if sub in s), None) # returns 'abc123'
If the match is at the end of the list or for very small lists, it doesn't make a difference, but consider this example:
import timeit
mylist = ['abc123'] + ['xyz123']*1000
sub = 'abc'
timeit.timeit('[s for s in mylist if sub in s]', setup='from __main__ import mylist, sub', number=100000)
# for me 7.949463844299316 with Python 2.7, 8.568840944994008 with Python 3.4
timeit.timeit('next((s for s in mylist if sub in s), None)', setup='from __main__ import mylist, sub', number=100000)
# for me 0.12696599960327148 with Python 2.7, 0.09955992100003641 with Python 3.4