2013-05-22 75 views
23

Tôi có một danh sách dài các số phao khác nhau, từ 1 đến 5, được gọi là "trung bình" và tôi muốn trả về danh sách các chỉ mục cho các phần tử nhỏ hơn hoặc lớn hơn than bTìm các chỉ mục của các phần tử phù hợp trong danh sách bằng Python

def find(lst,a,b): 
    result = [] 
    for x in lst: 
     if x<a or x>b: 
      i = lst.index(x) 
      result.append(i) 
    return result 

matches = find(average,2,4) 

Nhưng đáng ngạc nhiên, đầu ra cho "đối sánh" có nhiều sự lặp lại trong đó, ví dụ [2, 2, 10, 2, 2, 2, 19, 2, 10, 2, 2, 42, 2, 2, 10, 2, 2, 2, 10, 2, 2, ...].

Tại sao điều này lại xảy ra?

+0

Bản sao có thể có của [Cách tìm tất cả các lần xuất hiện của một phần tử trong danh sách?] (Https://stackoverflow.com/questions/6294179/how-to-find-all-occurrences-of-an-element-in -a-list) – Qiu

Trả lời

52

Bạn đang sử dụng .index() sẽ chỉ tìm thấy lần đầu tiên xuất hiện giá trị giá trị của bạn trong danh sách. Vì vậy, nếu bạn có giá trị 1.0 tại chỉ mục 2 và tại chỉ mục 9, thì .index(1.0) sẽ luôn trả lại 2, bất kể số lần 1.0 xảy ra trong danh sách.

Sử dụng enumerate() để thêm các chỉ số để lặp của bạn thay vì:

def find(lst, a, b): 
    result = [] 
    for i, x in enumerate(lst): 
     if x<a or x>b: 
      result.append(i) 
    return result 

Bạn có thể sụp đổ này vào danh sách hiểu:

def find(lst, a, b): 
    return [i for i, x in enumerate(lst) if x<a or x>b] 
+0

Bây giờ tôi hoàn toàn hiểu nó. Việc hiểu danh sách thực sự là một điều tốt, tôi vẫn đang cố gắng thích ứng với loại hình nhỏ gọn này bằng Python. Câu trả lời của bạn là tuyệt vời, cảm ơn rất nhiều! –

+0

Điều thú vị là kết quả sai với lặp lại có vẻ làm việc tốt cho việc sử dụng sau này của tôi, vì tôi muốn sử dụng nó để trích xuất các cột của một ma trận lớn. Có vẻ như sự lặp lại không ảnh hưởng đến việc cắt. –

+1

Bạn vẫn sẽ nhận được các giá trị chính xác trong danh sách của mình, cùng giá trị nằm ở chỉ mục 2 và bất kỳ chỉ số nào sau đó. Nhưng đó là một lỗi đang chờ để xảy ra, cắn bạn tại một số điểm khác trong mã của bạn. –

-1
>>> average = [1,3,2,1,1,0,24,23,7,2,727,2,7,68,7,83,2] 
>>> matches = [i for i in range(0,len(average)) if average[i]<2 or average[i]>4] 
>>> matches 
[0, 3, 4, 5, 6, 7, 8, 10, 12, 13, 14, 15] 
+0

Đây không phải là tất cả những gì OP muốn. – TerryA

+0

đọc lại câu hỏi: p – TerryA

+0

Tuy nhiên, 'liệt kê' là một người chiến thắng rõ ràng ở đây :) – root

2

Đó là một sự phụ thuộc khá nặng, nhưng nếu bạn' làm lại rất nhiều loại điều bạn nên cân nhắc sử dụng numpy.

In [56]: import random, numpy 

In [57]: lst = numpy.array([random.uniform(0, 5) for _ in xrange(1000)]) # example list 

In [58]: a, b = 1, 3 

In [59]: numpy.flatnonzero((lst > a) & (lst < b))[:10] 
Out[59]: array([ 0, 12, 13, 15, 18, 19, 23, 24, 26, 29]) 

Trả lời câu hỏi của Seanny123, tôi đã sử dụng mã thời gian này:

import numpy, timeit, random 

a, b = 1, 3 

lst = numpy.array([random.uniform(0, 5) for _ in xrange(1000)]) 

def numpy_way(): 
    numpy.flatnonzero((lst > 1) & (lst < 3))[:10] 

def list_comprehension(): 
    [e for e in lst if 1 < e < 3][:10] 

print timeit.timeit(numpy_way) 
print timeit.timeit(list_comprehension) 

Phiên bản numpy kết thúc nhanh hơn 60 lần.

+0

So sánh hiệu suất so với chỉ thực hiện việc hiểu danh sách là gì? Ngoài ra, tại sao sử dụng 'numpy.flatnonzero' trên' numpy.where'? – Seanny123

+1

Nhanh hơn 60 lần trong tay tôi. 'flatnonzero' đơn giản hơn' where', ở đây; bạn không cần kéo mảng chỉ mục ra khỏi bộ dữ liệu. –

Các vấn đề liên quan