Report this

What is the reason for this report?

Python Find String in List: Methods and Examples

Updated on June 16, 2026
Python Find String in List: Methods and Examples

Introduction

Finding a string in a list is one of the most common tasks in Python. You might do it to filter log data, check user input, look up configuration values, or work through text. The quickest way to check if a string is in a list is the in operator. It looks through the list one item at a time and returns True or False:

my_list = ["apple", "banana", "cherry"]
if "banana" in my_list:
    print("Found!")

Running this prints the following output:

Output
Found!

That one line answers the basic question, but real code often needs more. You might need the index of a match, all the positions where it matches, a substring match instead of an exact one, a case-insensitive search, or a pattern match using regular expressions.

This tutorial covers each approach with examples you can run, compares their speed and return types in one table, and shows three real-world cases (filtering logs, checking input, and matching file paths) so you can pick the right method for what you need. Every example runs in a standard Python 3.6+ environment (tested on the latest stable release, Python 3.14) and uses only the standard library, with no extra packages.

Key Takeaways

  • Use the in operator ("target" in my_list) for a fast, easy-to-read check; it returns True or False.
  • On a list, in checks for an exact match, not a partial one. So "app" in ["apple"] is False.
  • Use list.index("target") to get the position of the first match. Wrap it in a try/except ValueError block, since it raises an error when the string is not there.
  • To find all matching positions, use a list comprehension with enumerate(): [i for i, val in enumerate(my_list) if val == "target"].
  • To check if any element contains a substring, use any("sub" in item for item in my_list). To collect those elements, use a list comprehension.
  • Use next((item for item in my_list if "sub" in item), None) to get the first matching element (or a default) without checking the rest.
  • For case-insensitive matching, convert both sides with .lower(), or use re.search(pattern, item, re.IGNORECASE) for pattern searches.
  • Checking membership in a list is O(n) (it scans every item). If you search the same data many times, convert it to a set for O(1) average lookups, as noted in the Python Wiki time-complexity reference.
  • Use regular expressions only when you are matching a pattern (dates, extensions, IDs). For fixed text, plain in or str.find() is faster and easier to read.

Using the in operator to check if a string exists in a list

The in operator is the simplest and most common way to check whether a string is in a list, and it is the fastest choice for a one-time check. It returns True when a matching element exists and False when it does not. The matching not in operator checks that a string is missing.

l1 = ['A', 'B', 'C', 'D', 'A', 'A', 'C']

# Check whether a string is present in the list
if 'A' in l1:
    print('A is present in the list')

# Check whether a string is absent from the list
if 'X' not in l1:
    print('X is not present in the list')

This produces the following output:

Output
A is present in the list
X is not present in the list

The same pattern works well for checking user input. The following example asks the user for a value and reports whether it appears in the list:

l1 = ['A', 'B', 'C', 'D', 'A', 'A', 'C']
s = input('Please enter a character A-Z:\n')

if s in l1:
    print(f'{s} is present in the list')
else:
    print(f'{s} is not present in the list')

If the user types A, the program prints:

Output
Please enter a character A-Z:
A
A is present in the list

One thing to watch out for: on a list, in checks for an exact match, not a partial one. "app" in ["apple", "banana"] returns False because no element equals "app", even though "apple" starts with it. If you need to match a substring inside list elements, see the section on Searching for a substring within list elements. For more on the string formatting used here, see f-strings in Python.

Finding the index of a string with index()

When you need the position of a string instead of a yes/no answer, use the list index() method. It returns the index of the first match, counting from zero.

my_list = ["apple", "banana", "cherry"]
index = my_list.index("banana")
print(index)

This returns the position of the first match:

Output
1

The result 1 means "banana" is the second element, since list indexes start at 0. The key thing to remember is that index() raises a ValueError if the value is not there, so production code should wrap the call in a try/except block:

my_list = ["apple", "banana", "cherry"]
try:
    index = my_list.index("mango")
    print(f"Found at index {index}")
except ValueError:
    print("Not found")

Because "mango" is absent, the except branch runs and prints:

Output
Not found

Finding all indexes of a string in a list

The index() method only returns the first match. To get every position where a string appears, combine enumerate() with a list comprehension. This is a short, clean replacement for a manual while loop:

my_list = ["apple", "banana", "cherry", "banana"]
indexes = [i for i, val in enumerate(my_list) if val == "banana"]
print(indexes)

This returns a list of all matching indexes:

Output
[1, 3]

The comprehension checks each element and keeps the index when it matches the target. Learn more in the guides on list comprehensions and enumerate().

Searching for a substring within list elements

A common point of confusion is that in on a list checks for an exact match, when you may just want to know whether any element contains a target substring. The following patterns solve this and let you choose the result you need: the matching elements, a True/False answer, or just the first match.

Returning all elements that contain the substring

Use a list comprehension with the in operator (which does check for substrings inside individual strings) to collect every element that contains the target text:

my_list = ["apple", "banana", "cherry"]
matches = [item for item in my_list if "an" in item]
print(matches)

This keeps only the elements that contain "an":

Output
['banana']

Returning a boolean with any()

When you only need to know whether at least one element contains the substring, any() with a generator expression is the most efficient choice, since it stops at the first match:

my_list = ["apple.log", "banana.txt", "cherry.csv"]
has_log = any(".log" in item for item in my_list)
print(has_log)

This reports whether any element contains ".log":

Output
True

Returning the first match with next()

If you want only the first matching element and nothing else, next() over a generator expression returns it right away. It also takes a default value, which avoids a StopIteration error when there is no match:

my_list = ["app.log", "error.log", "data.csv"]
first_error = next((item for item in my_list if "error" in item), None)
print(first_error)

This returns the first element containing "error":

Output
error.log

Case-insensitive string search in a list

By default, every method above is case-sensitive, so "BANANA" will not match "banana". There are two reliable ways to make a search case-insensitive.

Normalizing with .lower()

The simplest approach is to convert both the target and each element to the same case with .lower() (or .upper()) before you compare them:

names = ["Alice", "BOB", "carol"]
target = "bob"
matches = [n for n in names if target.lower() in n.lower()]
print(matches)

This matches "BOB" regardless of case:

Output
['BOB']

Using re.IGNORECASE for pattern searches

When your search uses a pattern rather than a fixed string, pass the re.IGNORECASE flag to re.search() inside a comprehension. This is the cleaner choice when you also need regular-expression features:

import re

names = ["Alice", "BOB", "carol"]
matches = [n for n in names if re.search("bob", n, re.IGNORECASE)]
print(matches)

This returns the same case-insensitive result:

Output
['BOB']

Using regex to find strings in a list

Regular expressions are the right tool when you are searching for a pattern (a date, a file extension, an ID format) rather than a fixed string. The re module from the standard library handles these searches. For an introduction to the syntax, see An Introduction to Regular Expressions.

Filtering with re.search() and a list comprehension

re.search() returns a match object (which counts as True) when the pattern is found anywhere in the string, and None otherwise. Combine it with a comprehension to filter a list:

import re

logs = ["2024-01-01 OK", "2024-01-02 ERROR", "no date here"]
dated = [line for line in logs if re.search(r"\d{4}-\d{2}-\d{2}", line)]
print(dated)

This keeps only the lines that contain an ISO-style date:

Output
['2024-01-01 OK', '2024-01-02 ERROR']

Extracting matches with re.findall()

When you want the matched text itself rather than the whole element, re.findall() returns every match of the pattern in a string. Use a comprehension to combine the results across the list into one flat list:

import re

logs = ["2024-01-01 OK", "2024-01-02 ERROR", "no date here"]
dates = [match for line in logs for match in re.findall(r"\d{4}-\d{2}-\d{2}", line)]
print(dates)

This collects the date strings themselves:

Output
['2024-01-01', '2024-01-02']

When to use regex versus simple string methods

Use regex only when you truly need pattern matching. For an exact match, use the in operator or index(). For a fixed substring, use in on the element or str.find(). These plain methods are faster and much easier to read than a regular expression, and they avoid hard-to-spot bugs caused by unescaped special characters. Use regex when the target follows a flexible structure (for example, matching any .log or .txt extension, checking a date format, or pulling out numeric IDs) and a plain string cannot describe the rule.

Filtering a list by string pattern with list comprehension and filter()

Filtering a list down to the elements that match a string condition is so common that Python gives you two standard ways to do it. Both give the same result; the difference is mostly style.

Using a list comprehension

A list comprehension reads naturally and is the most common choice among Python developers for filtering a list:

words = ["cat", "dog", "caterpillar", "cobra"]
starts_with_cat = [w for w in words if w.startswith("cat")]
print(starts_with_cat)

This keeps the words that start with "cat":

Output
['cat', 'caterpillar']

Using filter() with a lambda

The built-in filter() function checks each element and returns an iterator, which you then turn into a list:

words = ["cat", "dog", "caterpillar", "cobra"]
starts_with_cat = list(filter(lambda w: w.startswith("cat"), words))
print(starts_with_cat)

This produces the identical result:

Output
['cat', 'caterpillar']

As a rule of thumb, use the list comprehension in most cases because it is easier to read. filter() can use slightly less memory for very large inputs because it processes items only as needed, and it reads cleanly when you already have a named function to pass instead of a lambda.

Counting occurrences with count()

When you need to know how many times a string appears rather than where it is, the list count() method returns the number of matches. A result of 0 means the string is not in the list.

l1 = ['A', 'B', 'C', 'D', 'A', 'A', 'C']
s = 'A'
count = l1.count(s)
if count > 0:
    print(f'{s} is present in the list {count} times.')

This reports the frequency of 'A':

Output
A is present in the list 3 times.

Using a loop (alternative approach)

The built-in methods cover almost every case, but a plain loop is worth knowing when you need to do extra work on each element during the search or want more control over how you loop through the list.

my_list = ["apple", "banana", "cherry", "banana"]
found = False
for item in my_list:
    if item == "banana":
        found = True
        break
print(found)

This stops at the first match and prints:

Output
True

This approach is longer and usually slower than the in operator for simple checks, so use the built-in methods unless the loop body does something a comprehension cannot express cleanly.

Method comparison: which approach should you use?

Each method fits a different goal. The following table matches common use cases to the recommended approach, what it returns, and its time complexity. The complexity figures follow the official Python Wiki time-complexity reference, where n is the number of elements in the list.

Method Use case Returns Time complexity Notes
in operator Check if an exact element exists bool O(n) Most readable membership test; exact match only
not in operator Check that an element is absent bool O(n) Negative membership test
list.index() Position of the first exact match int (or ValueError) O(n) Wrap in try/except ValueError
enumerate() + comprehension All positions of an exact match list[int] O(n) Returns every matching index
List comprehension with in All elements containing a substring list[str] O(n) Substring match on each element
any() Whether any element contains a substring bool O(n) Short-circuits at the first match
next() First element containing a substring str (or default) O(n) Returns one match, then stops
count() Number of occurrences int O(n) 0 means not present
re.search() in comprehension Pattern-based filtering list[str] O(n * m) m is pattern cost; use only for patterns
set membership (in) Repeated exact-match lookups bool O(1) average No substring matching; build the set once

Handling large datasets efficiently

When you work with large datasets, the cost of an O(n) scan adds up if you search the same data many times. A few changes to how you store the data can cut that cost a lot.

The most effective change is to use a set for repeated checks. Converting a list to a set with set(my_list) gives O(1) average lookups instead of O(n), because sets use hash tables instead of arrays. The trade-off is that sets do not keep order, drop duplicates, and cannot do substring matching, so they fit exact-match checks rather than pattern searches.

allowed = ["admin", "editor", "viewer", "guest"]
allowed_set = set(allowed)
print("editor" in allowed_set)

Because the lookup uses a hash table, this returns instantly even for very large collections:

Output
True

Two more options are worth knowing. Dictionaries give the same O(1) average lookup as sets, but they also map each key to a value, which is ideal when you need extra data and not just a yes/no answer. For data that is already sorted, the standard library bisect module finds elements in O(log n) time using binary search, which is faster than a full scan when you can keep the list in order.

Real-world examples

The patterns above are common in real Python code. Here are three practical examples of how you might use these string search methods in everyday tasks.

Filtering log lines that contain an error string

Scanning logs for lines that mention an error is a classic substring-filtering task, and a list comprehension solves it cleanly:

log_lines = [
    "INFO startup complete",
    "ERROR database connection failed",
    "WARNING disk almost full",
    "ERROR timeout while reading socket",
]
errors = [line for line in log_lines if "ERROR" in line]
print(errors)

This isolates the two error lines:

Output
['ERROR database connection failed', 'ERROR timeout while reading socket']

Checking user input against an allowed values list

Checking that a submitted value is one of a known set is an exact-match check. Building a set first keeps the check fast even when you validate many inputs:

allowed_roles = {"admin", "editor", "viewer"}
submitted = "editor"
if submitted in allowed_roles:
    print(f"{submitted} is a valid role")
else:
    print(f"{submitted} is not allowed")

Because "editor" is in the set, this prints:

Output
editor is a valid role

Extracting file paths that match a pattern

Picking files by extension or naming convention is a job for regular expressions, since the target is a pattern rather than a fixed string:

import re

paths = ["report.csv", "image.png", "data.csv", "notes.txt"]
csv_files = [p for p in paths if re.search(r"\.csv$", p)]
print(csv_files)

This keeps only the paths ending in .csv:

Output
['report.csv', 'data.csv']

FAQs

1. How to search a string in a list in Python?

The fastest way to search for an exact string is the in operator, which returns True or False. Use it whenever you only need to know whether the string is there:

my_list = ["apple", "banana", "cherry"]
if "banana" in my_list:
    print("Found!")

If you need the position instead of a True/False answer, use index() inside a try/except block so a missing value does not crash your program:

my_list = ["apple", "banana", "cherry"]
try:
    index = my_list.index("banana")
    print(f"Found at index {index}")
except ValueError:
    print("Not found")

2. How to check if a string exists in a list in Python?

Use the in operator, which is the standard way to check membership and returns True or False directly. It reads almost like plain English and is the best default for a yes/no check:

my_list = ["apple", "banana", "cherry"]
if "banana" in my_list:
    print("Exists")
else:
    print("Does not exist")

3. How to find part of a string in a list?

To find elements that contain a substring (rather than equal it exactly), use a list comprehension with the in operator, because in checks for substrings inside individual strings. This returns every element that contains the target text:

my_list = ["apple", "banana", "cherry"]
part = "an"
filtered_list = [item for item in my_list if part in item]
print(filtered_list)  # ['banana']

For a simple yes/no answer instead of the matching items, use any(part in item for item in my_list).

4. How do I find a specific string in Python?

To find a specific string and get its position, use the index() method, which returns the index of the first match and raises ValueError if the string is missing. Always wrap it in try/except so a missing value is handled gracefully:

my_list = ["apple", "banana", "cherry"]
try:
    index = my_list.index("banana")
    print(f"Found at index {index}")
except ValueError:
    print("Not found")

5. How to count occurrences of a string in a list?

Use the list count() method, which returns how many times a value appears. A return value of 0 means the string is not in the list:

my_list = ["apple", "banana", "cherry", "banana"]
count = my_list.count("banana")
print(f"Count: {count}")  # 2

6. How to find all indexes of a string in a list?

Use a list comprehension with enumerate() to collect every index where the string appears, since index() returns only the first one. This gives you a list of all matching positions:

my_list = ["apple", "banana", "cherry", "banana"]
indexes = [i for i, val in enumerate(my_list) if val == "banana"]
print(indexes)  # [1, 3]

7. How do I perform a case-insensitive string search in a Python list?

The simplest approach is to convert both the target and each element to the same case with .lower() (or .upper()) before comparing them. This matches no matter how the text is capitalized:

items = ["Apple", "BANANA", "Cherry"]
target = "banana"
matches = [item for item in items if target.lower() in item.lower()]
print(matches)  # ['BANANA']

When the search uses a pattern, use re.search("target", item, re.IGNORECASE) inside a comprehension instead.

8. When should I use regex to find strings in a list?

Use regular expressions when the target is a pattern rather than fixed text, such as a date format, a file extension, or a structured ID. For exact or simple substring matching, the plain in operator or str.find() is faster and easier to read:

import re
files = ["a.log", "b.txt", "c.log"]
logs = [f for f in files if re.search(r"\.log$", f)]
print(logs)  # ['a.log', 'c.log']

9. What is the time complexity of finding a string in a Python list?

Methods that scan the whole list, such as the in operator, index(), count(), and list comprehensions, are O(n), which means the cost grows with the length of the list. If you need to run many checks on the same data, convert the list to a set once for O(1) average lookups, as documented in the Python Wiki time-complexity reference. Keep in mind that sets support only exact matching, not substring searches.

10. What is the difference between list.index() and list.find() in Python?

Python lists do not have a find() method, so calling my_list.find(...) raises an AttributeError. The find() method belongs to strings and returns -1 when the substring is missing. For lists, use index() (which raises ValueError if the value is missing) or a list comprehension when you need to find elements:

text = "banana"
print(text.find("na"))   # 2  (string method)

fruits = ["apple", "banana"]
print(fruits.index("banana"))  # 1  (list method)

Conclusion

In this tutorial, you learned how to find a string in a Python list using the right tool for each goal: the in operator for fast membership checks, index() and enumerate() for positions, list comprehensions and any()/next() for substring searches, .lower() and re.IGNORECASE for case-insensitive matching, regular expressions for pattern matching, and filter() as an alternative to comprehensions. You also saw how a set turns repeated O(n) scans into O(1) lookups, and how these patterns apply to log filtering, input validation, and file-path matching.

For most situations, the in operator is the best default. Use index() when you need a position, comprehensions when you need substring matches, and regular expressions only when you are matching a pattern.

Further reading

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the author(s)

Pankaj Kumar
Pankaj Kumar
Author
See author profile

Java and Python Developer for 20+ years, Open Source Enthusiast, Founder of https://www.askpython.com/, https://www.linuxfordevices.com/, and JournalDev.com (acquired by DigitalOcean). Passionate about writing technical articles and sharing knowledge with others. Love Java, Python, Unix and related technologies. Follow my X @PankajWebDev

Anish Singh Walia
Anish Singh Walia
Editor
Sr Technical Content Strategist and Team Lead
See author profile

I help Businesses scale with AI x SEO x (authentic) Content that revives traffic and keeps leads flowing | 3,000,000+ Average monthly readers on Medium | Sr Technical Writer(Team Lead) @ DigitalOcean | Ex-Cloud Consultant @ AMEX | Ex-Site Reliability Engineer(DevOps)@Nutanix

Manikandan Kurup
Manikandan Kurup
Editor
Senior Technical Content Engineer I
See author profile

With over 6 years of experience in tech publishing, Mani has edited and published more than 75 books covering a wide range of data science topics. Known for his strong attention to detail and technical knowledge, Mani specializes in creating clear, concise, and easy-to-understand content tailored for developers.

Category:
Tags:

Still looking for an answer?

Was this helpful?
Creative CommonsThis work is licensed under a Creative Commons Attribution-NonCommercial- ShareAlike 4.0 International License.
Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

The developer cloud

Scale up as you grow — whether you're running one virtual machine or ten thousand.

Start building today

From GPU-powered inference and Kubernetes to managed databases and storage, get everything you need to build, scale, and deploy intelligent applications.

Dark mode is coming soon.