2009-12-08 30 views
5

Tôi muốn xóa phần tử khỏi danh sách, sao cho thành phần đó chứa 'X' hoặc 'N'. Tôi phải áp dụng cho một bộ gen lớn. Dưới đây là một ví dụ:Xóa phần tử khỏi danh sách dựa trên biến vị ngữ

đầu vào:

codon=['AAT','XAC','ANT','TTA'] 

đầu ra mong đợi:

codon=['AAT','TTA'] 
+2

Khi bạn tìm trong trang tham chiếu Python để "xóa" khỏi "danh sách", bạn tìm thấy gì? Có gì không? Vui lòng kiểm tra tài liệu Python, và sau đó cập nhật câu hỏi của bạn với một cái gì đó cụ thể. –

+0

Gợi ý: Bắt đầu tìm kiếm của bạn tại đây: http://docs.python.org/library/stdtypes.html#sequence-types-str-unicode-list-tuple-buffer-xrange –

+0

Câu hỏi được nêu rõ ràng. –

Trả lời

2

Ngoài ra còn có phương pháp làm việc đó sử dụng bộ lọc

list = filter(lambda x: 'X' not in x and 'N' not in x, list) 
6

Đối với mục đích cơ sở

>>> [x for x in ['AAT','XAC','ANT','TTA'] if "X" not in x and "N" not in x] 
['AAT', 'TTA'] 

Nhưng nếu bạn có số lượng lớn dữ liệu, tôi khuyên bạn nên sử dụng dict hoặc thiết lập

Và Nếu bạn có nhiều nhân vật khác hơn X và N, bạn có thể làm như thế này

>>> [x for x in ['AAT','XAC','ANT','TTA'] if not any(ch for ch in list(x) if ch in ["X","N","Y","Z","K","J"])] 
['AAT', 'TTA'] 

LƯU Ý: list(x) có thể chỉ là x["X","N","Y","Z","K","J"] có thể chỉ là "XNYZKJ" và tham khảo câu trả lời của gnibbler, Anh ấy đã làm tốt nhất.

+0

Bạn vừa đánh tôi với nó. Tôi có cùng một câu trả lời. –

+0

mang nó, một nhanh nhất –

+0

Phải có cách tốt hơn để viết điều kiện. một cái gì đó giống như len (set ("x n".split()) | thiết lập (x)) == 0 tốt đẹp và dễ dàng nếu bạn có nhiều thứ để loại bỏ nhưng nó có khả năng là chậm hơn. –

2
  1. filter(lambda x: 'N' not in x or 'X' not in x, your_list)
  2. your_list = [x for x in your_list if 'N' not in x or 'X' not in x]
+0

Điều kiện ở đây là sai. Nó hoặc là '' N 'không phải trong x và' X 'không phải trong x', OR 'không (' N 'trong x hoặc' X 'trong x)'. –

4

Một cách khác không nhanh nhất nhưng tôi nghĩ rằng nó đọc độc đáo

>>> [x for x in ['AAT','XAC','ANT','TTA'] if not any(y in x for y in "XN")] 
['AAT', 'TTA'] 

>>> [x for x in ['AAT','XAC','ANT','TTA'] if not set("XN")&set(x)] 
['AAT', 'TTA'] 

Bằng cách này sẽ nhanh hơn cho codon dài (giả sử có một số sự lặp lại)

codon = ['AAT','XAC','ANT','TTA'] 
def pred(s,memo={}): 
    if s not in memo: 
     memo[s]=not any(y in s for y in "XN") 
    return memo[s] 

print filter(pred,codon) 

Dưới đây là phương pháp được đề xuất bởi James Brooks, bạn phải kiểm tra để xem đó là nhanh hơn cho dữ liệu của bạn

codon = ['AAT','XAC','ANT','TTA'] 
def pred(s,memo={}): 
    if s not in memo: 
     memo[s]= not set("XN")&set(s) 
    return memo[s] 

print filter(pred,codon) 

Đối với codon mẫu này, phiên bản sử dụng bộ là chậm hơn khoảng 10%

+0

Bạn luôn có đoạn mã ngắn nhất, :-) +1 – YOU

+0

Đây là câu trả lời hay nhất! – YOU

+0

Rất tuyệt! Mã cho 'pred' có thể sử dụng phương thức dict.setdefault được xây dựng sẵn (như được minh họa trong câu trả lời của tôi); Tôi đoán rằng phiên bản setdefault nhanh hơn. – EOL

0

Như S.Mark yêu cầu ở đây là phiên bản của tôi. Nó có thể chậm hơn nhưng làm cho nó dễ dàng hơn để thay đổi những gì được loại bỏ.

def filter_genome(genome, killlist = set("X N".split()): 
    return [codon for codon in genome if 0 == len(set(codon) | killlist)] 
+0

Toán tử thiết lập trong câu trả lời này phải là '&', không phải '|'. –

2

Bất kỳ lý do gì để sao chép toàn bộ danh sách? Làm thế nào về:

>>> def pred(item, haystack="XN"): 
...  return any(needle in item for needle in haystack) 
... 
>>> lst = ['AAT', 'XAC', 'ANT', 'TTA'] 
>>> idx = 0 
>>> while idx < len(lst): 
...  if pred(lst[idx]): 
...   del lst[idx] 
...  else: 
...   idx = idx + 1 
... 
>>> lst 
['AAT', 'TTA'] 

Tôi biết rằng comprehensions danh sách là tất cả các cơn thịnh nộ những ngày này, nhưng nếu danh sách dài chúng ta không muốn lặp lại điều đó mà không bất kỳ lý do đúng không? Bạn có thể thực hiện việc này ở bước tiếp theo và tạo một hàm tiện ích tốt đẹp:

>>> def remove_if(coll, predicate): 
...  idx = len(coll) - 1 
...  while idx >= 0: 
...   if predicate(coll[idx]): 
...    del coll[idx] 
...   idx = idx - 1 
...  return coll 
... 
>>> lst = ['AAT', 'XAC', 'ANT', 'TTA'] 
>>> remove_if(lst, pred) 
['AAT', 'TTA'] 
>>> lst 
['AAT', 'TTA'] 
+0

Đây là cách một nhà phát triển C sẽ suy nghĩ về vấn đề này. Bằng cách sử dụng Python, trong các danh sách cụ thể, bạn đã hy sinh rất nhiều hiệu quả, vậy tại sao bạn quan tâm đến việc sửa đổi danh sách tại chỗ? –

+0

Trên thực tế, một nhà phát triển C++ ... Tôi nghĩ rằng việc sửa đổi nó tại chỗ là những gì OP yêu cầu. Tôi thường quan tâm đến hiệu quả ngay cả khi tập dữ liệu lớn cũng vì sao chép bộ nhớ lớn thường có nghĩa là giờ thay vì phút hoặc hết bộ nhớ nếu bạn đang xử lý các tập dữ liệu lớn. Chưa kể rằng việc hiểu danh sách và một loạt các 'không' và' và' cùng nhau ẩn những gì bạn đang thực sự làm. Thay vì _removing một vài mục từ một list_ bạn thấy _duplicating một danh sách mà không có items_. Tôi đoán tôi thích sự đơn giản và rõ ràng hơn. –

+1

Phải là 'idx = idx - 1' trong ví dụ thứ hai. Lý do cho việc sử dụng tính năng list comprehensions hoặc filter() là vòng lặp nằm trong C, vì vậy thường nhanh hơn nhiều. –

1

Tôi thích phương pháp ghi nhớ của gnibbler rất nhiều. Một trong hai phương pháp sử dụng ghi nhớ phải giống hệt nhau trong bức tranh lớn trên các tập dữ liệu lớn, vì từ điển ghi nhớ phải được điền nhanh và thử nghiệm thực tế hiếm khi được thực hiện.Với điều này trong tâm trí, chúng ta sẽ có thể cải thiện hiệu suất nhiều hơn cho các tập dữ liệu lớn. (Điều này đến với một số chi phí cho những người rất nhỏ, nhưng ai quan tâm đến những người đó?) Đoạn mã sau chỉ phải tra cứu một mục trong memo dict một lần khi nó có mặt, thay vì hai lần (một lần để xác định thành viên, khác để trích xuất giá trị).

codon = ['AAT', 'XAC', 'ANT', 'TTA'] 
def pred(s,memo={}): 
    try: 
     return memo[s] 
    except KeyError: 
     memo[s] = not any(y in s for y in "XN") 
    return memo[s] 

filtered = filter(pred, codon) 

Như tôi đã nói, điều này đáng chú ý là nhanh hơn khi bộ gen lớn (hoặc ít nhất là không quá nhỏ).

Nếu bạn không muốn lặp lại danh sách, nhưng chỉ lặp qua danh sách lọc, làm điều gì đó như:

for item in (item for item in codon if pred): 
    do_something(item) 
+0

Thử ... ngoại trừ cấu trúc mà bạn sử dụng là khá tương đương với dict.setdefault được tích hợp sẵn (xem câu trả lời của tôi cho ví dụ). – EOL

+0

Thực sự có một sự khác biệt tinh tế: với setdefault, cụm từ "mặc định" được đánh giá bất kể là gì! Biểu thức này chứa vị từ chậm mà chúng tôi đang cố gắng tránh và làm cho việc ghi nhớ vô dụng. Phiên bản try/except chỉ đánh giá vị từ khi có một KeyError. – musicinmybrain

+0

@musicinmybrain: bắt được! Cảm ơn! – EOL

0

Nó được (asympotically) nhanh hơn để sử dụng một biểu thức chính quy hơn tìm kiếm nhiều lần trong cùng một chuỗi cho một ký tự nhất định: trên thực tế, với biểu thức chính quy, các chuỗi chỉ được đọc nhiều nhất một lần (thay vì hai lần khi không tìm thấy các chữ cái trong câu trả lời gốc của gnibbler). Với memoization gnibbler của, cách tiếp cận biểu hiện thường xuyên đọc:

import re 
remove = re.compile('[XN]').search 

codon = ['AAT','XAC','ANT','TTA'] 
def pred(s,memo={}): 
    if s not in memo: 
     memo[s]= not remove(s) 
    return memo[s] 

print filter(pred,codon) 

này nên được (tiệm cận) nhanh hơn bằng cách sử dụng "trong s" hoặc "đặt" kiểm tra (ví dụ, các mã trên nên nhanh hơn cho các chuỗi thời gian đủ dài s).

Tôi ban đầu nghĩ rằng câu trả lời của gnibbler có thể được viết bằng một cách nhanh hơn và nhỏ gọn hơn với dict.setdefault():

codon = ['AAT','XAC','ANT','TTA'] 
def pred(s,memo={}): 
    return memo.setdefault(s, not any(y in s for y in "XN")) 

print filter(pred,codon) 

Tuy nhiên, như gnibbler lưu ý, giá trị trong setdefault luôn được đánh giá (mặc dù về nguyên tắc, nó chỉ có thể được đánh giá khi không tìm thấy khóa từ điển).

+0

Hãy nhớ rằng tham số thứ hai để setdefault luôn luôn được đánh giá mặc dù, đánh bại memoization –

+0

@gnibbler: bạn nói đúng, cảm ơn! – EOL

1

Nếu bạn đang xử lý các danh sách cực lớn, bạn muốn sử dụng các phương pháp không liên quan đến việc vượt qua toàn bộ danh sách bất kỳ thứ gì bạn cần.

Tốt nhất là khả năng được tạo ra một chức năng lọc, và sử dụng itertools.ifilter, ví dụ .:

new_seq = itertools.ifilter(lambda x: 'X' in x or 'N' in x, seq) 

này trì hoãn thực sự thử nghiệm mọi phần tử trong danh sách cho đến khi bạn thực sự lặp trên nó. Lưu ý rằng bạn có thể lọc một chuỗi lọc cũng giống như bạn có thể trình tự ban đầu:

new_seq1 = itertools.ifilter(some_other_predicate, new_seq) 

Edit:

Ngoài ra, một thử nghiệm nhỏ cho thấy memoizing tìm thấy các mục trong một bộ có khả năng cung cấp đủ cải tiến đáng để làm và sử dụng cụm từ thông dụng có thể không phải là cách để đi:

seq = ['AAT','XAC','ANT','TTA'] 
>>> p = re.compile('[X|N]') 
>>> timeit.timeit('[x for x in seq if not p.search(x)]', 'from __main__ import p, seq') 
3.4722548536196314 
>>> timeit.timeit('[x for x in seq if "X" not in x and "N" not in x]', 'from __main__ import seq') 
1.0560532134670666 
>>> s = set(('XAC', 'ANT')) 
>>> timeit.timeit('[x for x in seq if x not in s]', 'from __main__ import s, seq') 
0.87923730529996647 
+0

tuy nhiên new_seq là một trình tạo tiền phạt nếu bạn chỉ muốn lặp lại nó, nhưng đôi khi bạn sẽ cần danh sách thay thế. –

+0

Nếu bạn đang làm việc với các danh sách cực lớn, bất kỳ nơi nào bạn đang sử dụng danh sách thay vì lặp lại có thể là một điểm khó khăn. Bạn có thể trivially chuyển đổi một máy phát điện thành một danh sách - 'list (new_seq)' làm điều đó - nhưng nó làm điều đó bằng cách truy cập mọi phần tử trong danh sách. Nếu bạn đang làm việc với một danh sách vài triệu codon, bạn thực sự chỉ muốn làm điều đó một lần. –

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