tl; dr
Một biểu thức trình tạo có lẽ là giải pháp hiệu quả và đơn giản nhất cho vấn đề của bạn:
l = [(1,"juca"),(22,"james"),(53,"xuxa"),(44,"delicia")]
result = next((i for i, v in enumerate(l) if v[0] == 53), None)
# 2
Giải trình
Có một số câu trả lời cung cấp một giải pháp đơn giản cho câu hỏi này bằng cách hiểu danh sách. Mặc dù những câu trả lời này là hoàn toàn chính xác, nhưng chúng không phải là tối ưu. Tùy thuộc vào trường hợp sử dụng của bạn, có thể có những lợi ích đáng kể khi thực hiện một vài sửa đổi đơn giản.
Vấn đề chính mà tôi thấy khi sử dụng khả năng hiểu danh sách cho trường hợp sử dụng này là toàn bộ danh sách sẽ được xử lý, mặc dù bạn chỉ muốn tìm 1 phần tử .
Python cung cấp một cấu trúc đơn giản, lý tưởng ở đây. Nó được gọi là biểu thức máy phát điện . Đây là một ví dụ:
# Our input list, same as before
l = [(1,"juca"),(22,"james"),(53,"xuxa"),(44,"delicia")]
# Call next on our generator expression.
next((i for i, v in enumerate(l) if v[0] == 53), None)
Chúng ta có thể mong đợi phương pháp này về cơ bản hoạt động giống như cách hiểu danh sách trong ví dụ nhỏ của chúng ta, nhưng điều gì sẽ xảy ra nếu chúng ta đang làm việc với một tập dữ liệu lớn hơn? Đó là nơi phát huy lợi thế của việc sử dụng phương pháp máy phát điện. Thay vì tạo danh sách mới, chúng tôi sẽ sử dụng danh sách hiện có của bạn làm danh sách có thể lặp lại của chúng tôi và sử dụng next()
để lấy mục đầu tiên từ trình tạo của chúng tôi.
Hãy xem các phương pháp này hoạt động khác nhau như thế nào trên một số tập dữ liệu lớn hơn. Đây là những danh sách lớn, được tạo từ 10000000 + 1 phần tử, với mục tiêu của chúng tôi ở đầu (tốt nhất) hoặc cuối (tệ nhất). Chúng tôi có thể xác minh rằng cả hai danh sách này sẽ hoạt động như nhau bằng cách sử dụng cách hiểu danh sách sau:
Liệt kê các kiến thức
"Trường hợp xấu nhất"
worst_case = ([(False, 'F')] * 10000000) + [(True, 'T')]
print [i for i, v in enumerate(worst_case) if v[0] is True]
# [10000000]
# 2 function calls in 3.885 seconds
#
# Ordered by: standard name
#
# ncalls tottime percall cumtime percall filename:lineno(function)
# 1 3.885 3.885 3.885 3.885 so_lc.py:1(<module>)
# 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
"Trường hợp tốt nhất"
best_case = [(True, 'T')] + ([(False, 'F')] * 10000000)
print [i for i, v in enumerate(best_case) if v[0] is True]
# [0]
# 2 function calls in 3.864 seconds
#
# Ordered by: standard name
#
# ncalls tottime percall cumtime percall filename:lineno(function)
# 1 3.864 3.864 3.864 3.864 so_lc.py:1(<module>)
# 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
Biểu thức trình tạo
Đây là giả thuyết của tôi về máy phát điện: chúng ta sẽ thấy rằng máy phát điện sẽ hoạt động tốt hơn đáng kể trong trường hợp tốt nhất, nhưng cũng tương tự trong trường hợp xấu nhất. Mức tăng hiệu suất này chủ yếu là do trình tạo được đánh giá một cách lười biếng, có nghĩa là nó sẽ chỉ tính toán những gì cần thiết để mang lại một giá trị.
Trường hợp xấu nhất
# 10000000
# 5 function calls in 1.733 seconds
#
# Ordered by: standard name
#
# ncalls tottime percall cumtime percall filename:lineno(function)
# 2 1.455 0.727 1.455 0.727 so_lc.py:10(<genexpr>)
# 1 0.278 0.278 1.733 1.733 so_lc.py:9(<module>)
# 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
# 1 0.000 0.000 1.455 1.455 {next}
Trường hợp tốt nhất
best_case = [(True, 'T')] + ([(False, 'F')] * 10000000)
print next((i for i, v in enumerate(best_case) if v[0] == True), None)
# 0
# 5 function calls in 0.316 seconds
#
# Ordered by: standard name
#
# ncalls tottime percall cumtime percall filename:lineno(function)
# 1 0.316 0.316 0.316 0.316 so_lc.py:6(<module>)
# 2 0.000 0.000 0.000 0.000 so_lc.py:7(<genexpr>)
# 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
# 1 0.000 0.000 0.000 0.000 {next}
GÌ?! Trường hợp tốt nhất thổi bay khả năng hiểu danh sách, nhưng tôi không mong đợi trường hợp xấu nhất của chúng tôi có thể làm tốt hơn khả năng hiểu danh sách ở mức độ như vậy. Làm như thế nào? Thành thật mà nói, tôi chỉ có thể suy đoán mà không cần nghiên cứu thêm.
Hãy xem tất cả những điều này bằng một hạt muối, tôi không chạy bất kỳ hồ sơ mạnh mẽ nào ở đây, chỉ là một số thử nghiệm rất cơ bản. Điều này đủ để đánh giá cao rằng biểu thức trình tạo hoạt động hiệu quả hơn cho kiểu tìm kiếm danh sách này.
Lưu ý rằng đây là tất cả cơ bản, được tích hợp sẵn trong python. Chúng tôi không cần nhập bất kỳ thứ gì hoặc sử dụng bất kỳ thư viện nào.
Lần đầu tiên tôi thấy kỹ thuật này để tìm kiếm trong khóa học Udacity cs212 với Peter Norvig.