2010-03-25 46 views

Trả lời

86
>>> a = range(1, 10) 
>>> [x for x in a if x not in [2, 3, 7]] 
[1, 4, 5, 6, 8, 9] 
+7

Nếu tôi có danh sách '[1,2,2,2,3,4]' và danh sách con '[2,3]', thì kết quả sẽ là '[1,2,2,4 ] ', có cách nào để làm điều đó không? – user

+0

@user điều này giúp bạn hầu hết các cách có - nhưng vấn đề của bạn là một vấn đề khác nhau! l = [1,2,2,3,4] sl = [2,3] [x cho x trong [l [n: n + 2] cho n trong phạm vi (0, len (l)) [ :: 2]] nếu x! = Sl] – jsh

11
a = range(1,10) 
itemsToRemove = set([2, 3, 7]) 
b = filter(lambda x: x not in itemsToRemove, a) 

hoặc

b = [x for x in a if x not in itemsToRemove] 

Đừng tạo ra các thiết lập bên trong hoặc bên trong lambda hiểu. Nếu bạn làm thế, nó sẽ được tái tạo trên mỗi lần lặp lại, đánh bại điểm của việc sử dụng một tập hợp.

+1

Trừ khi nó tạo N bộ, N là len (a). – FogleBird

+0

Nó chỉ tạo một bộ khi tạo hàm lambda –

+0

Điểm tốt, FogleBird. Cần tạo ra nó bên ngoài lambda hoặc danh sách hiểu. – Yaroslav

5

Những người khác có các cách được đề xuất để tạo danh sách mới sau khi lọc, ví dụ:

newl = [x for x in l if x not in [2,3,7]] 

hoặc

newl = filter(lambda x: x not in [2,3,7], l) 

nhưng từ câu hỏi của bạn có vẻ bạn muốn tại chỗ sửa đổi cho rằng bạn có thể làm điều này, điều này cũng sẽ nhanh hơn nhiều nếu danh sách ban đầu có chiều dài và các mặt hàng phải được loại bỏ ít

l = range(1,10) 
for o in set([2,3,7,11]): 
    try: 
     l.remove(o) 
    except ValueError: 
     pass 

print l 

đầu ra: [1, 4, 5, 6, 8, 9]

Tôi đang kiểm tra ngoại lệ ValueError để nó hoạt động ngay cả khi các mục không có trong danh sách gốc.

Ngoài ra, nếu bạn không cần giải pháp sửa đổi tại chỗ theo số S.Mark thì đơn giản hơn.

+0

nếu bạn thực sự cần sửa đổi tại chỗ, các câu trả lời trước đó có thể được sửa đổi thành: 'a [:] = [x cho x trong a nếu x không phải trong [2,3,7]]'. Điều này sẽ nhanh hơn mã của bạn. –

+2

có một [:] có thể được sử dụng, nhưng nó không rõ ràng rằng nó sẽ nhanh hơn, cho danh sách dài với vài giá trị để loại bỏ mã của tôi sẽ nhanh hơn nhiều, ví dụ: thử danh sách để xóa = [1] :) –

+0

@Anurag: Bạn có vẻ đúng; kiểm tra thời gian làm cho nó trông giống như loại bỏ tại chỗ là nhanh hơn. –

5

Cách đơn giản nhất là

>>> a = range(1, 10) 
>>> for x in [2, 3, 7]: 
... a.remove(x) 
... 
>>> a 
[1, 4, 5, 6, 8, 9] 

Một vấn đề có thể ở đây là mỗi lần bạn gọi remove(), tất cả các mục được xáo trộn xuống danh sách để lấp đầy lỗ. Vì vậy, nếu a phát triển rất lớn, điều này sẽ kết thúc khá chậm.

Cách này tạo danh sách hoàn toàn mới. Ưu điểm là chúng ta tránh tất cả các xáo trộn trong những cách tiếp cận đầu tiên

>>> removeset = set([2, 3, 7]) 
>>> a = [x for x in a if x not in removeset] 

Nếu bạn muốn thay đổi a tại chỗ, chỉ một thay đổi nhỏ là cần thiết

>>> removeset = set([2, 3, 7]) 
>>> a[:] = [x for x in a if x not in removeset] 
+0

@gnibbler, Yêu cầu của bạn * "Vì vậy, nếu' a' phát triển rất lớn, điều này sẽ kết thúc là khá chậm. "* Là một chút gây hiểu lầm. Nếu chỉ có độ dài 'a' là không bị chặn, tất cả các đoạn mã bạn cung cấp là O (n). Vấn đề ** thực ** với 'remove' là nó chỉ xóa * lần xuất hiện đầu tiên * của các đối số của nó, không phải tất cả các lần xuất hiện. Nó cũng thường phù hợp hơn với việc viết mã rõ ràng, thành ngữ để tạo danh sách mới thay vì thay đổi danh sách cũ. –

+0

@ Giống như vậy, tôi đã cố giữ câu trả lời đơn giản vì OP đã sử dụng thẻ mới bắt đầu. –

+3

"đơn giản" không phải là lý do cho * không chính xác *. –

4
>>> a=range(1,10) 
>>> for i in [2,3,7]: a.remove(i) 
... 
>>> a 
[1, 4, 5, 6, 8, 9] 

>>> a=range(1,10) 
>>> b=map(a.remove,[2,3,7]) 
>>> a 
[1, 4, 5, 6, 8, 9] 
+0

Không sử dụng 'bản đồ' cho các tác dụng phụ. 'map' là để thu thập kết quả của một loạt các cuộc gọi. Đối với vòng lặp là công cụ để làm điều gì đó nhiều lần. –

+0

nếu những gì bạn có ý nghĩa bởi tác dụng phụ là những "không" trở lại bởi 'bản đồ', sau đó nó có thể" che giấu "tắt. Khác hơn thế, nó vẫn hợp lệ, và tôi thích sự đồng nhất của nó. – ghostdog74

29

Nếu bạn không có giá trị lặp lại, bạn có thể sử dụng chênh lệch đặt.

x = set(range(10)) 
y = x - set([2, 3, 7]) 
# y = set([0, 1, 4, 5, 6, 8, 9]) 

và sau đó chuyển đổi lại danh sách, nếu cần.

+0

Lưu ý rằng điều này sẽ làm xáo trộn danh sách kết quả. –

+1

Thứ tự của danh sách có thể thay đổi, nhưng theo một cách xác định. Nó không phải là "xáo trộn" theo nghĩa ngẫu nhiên. – dansalmo

+3

cũng vậy, nếu danh sách ban đầu của bạn x có bản sao, sau khi thao tác set(), chỉ có một lần được lưu. –

14

Tôi đang tìm cách nhanh để thực hiện chủ đề, vì vậy tôi đã thực hiện một số thử nghiệm với các cách được đề xuất. Và tôi đã ngạc nhiên bởi kết quả, vì vậy tôi muốn chia sẻ nó với bạn.

Các thí nghiệm được thực hiện bằng pythonbenchmark công cụ và với

a = range(1,50000) # Source list 
b = range(1,15000) # Items to remove 

Kết quả:

def comprehension(a, b): 
    return [x for x in a if x not in b] 

5 cố gắng, thời gian trung bình 12,8 giây

def filter_function(a, b): 
    return filter(lambda x: x not in b, a) 

5 cố gắng, thời gian trung bình 12,6 sec

def modification(a,b): 
    for x in b: 
     try: 
      a.remove(x) 
     except ValueError: 
      pass 
    return a 

5 cố gắng, thời gian trung bình 0.27 giây

def set_approach(a,b): 
    return list(set(a)-set(b)) 

5 cố gắng, thời gian trung bình 0,0057 giây

Ngoài ra tôi làm một phép đo với kích thước đầu vào lớn hơn cho hai chức năng cuối cùng

a = range(1,500000) 
b = range(1,100000) 

Và kết quả:

Đối với sửa đổi (loại bỏ phương pháp) - Thời gian trung bình là 252 giây Đối với cách tiếp cận thiết lập - thời gian trung bình là 0,75 giây

Vì vậy, bạn có thể thấy cách tiếp cận với bộ được đáng kể nhanh hơn so với những người khác. Có, nó không giữ các mặt hàng tương tự, nhưng nếu bạn không cần nó - đó là dành cho bạn. Và hầu như không có sự khác biệt giữa danh sách hiểu và sử dụng chức năng lọc. Sử dụng 'remove' nhanh hơn gấp 50 lần, nhưng nó sửa đổi danh sách nguồn. Và lựa chọn tốt nhất là sử dụng bộ - nhanh hơn 1000 lần so với việc hiểu danh sách!

+0

rất thú vị. Tôi sẽ không được sử dụng thiết lập, trực giác chuyển đổi nên thêm chi phí. rõ ràng trực giác của tôi đã sai. cảm ơn vì sự thấu hiểu – lhk

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