2009-10-08 39 views
88

Tôi có một danh sách mà tôi muốn thay thế các giá trị bằng None ở đâu điều kiện() trả về True.Thay thế các giá trị trong danh sách bằng cách sử dụng Python

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 

Ví dụ, nếu kiểm tra tình trạng bool (mục% 2) phải trả:

[None, 1, None, 3, None, 5, None, 7, None, 9, None] 

cách hiệu quả nhất để làm điều này là gì?

+0

sử dụng mô đun itertools, đây là mô-đun hiệu quả nhất. – LtWorf

+1

Để biết các so sánh thay thế 'tại chỗ ', hãy xem [answer] này (http://stackoverflow.com/a/24203748/307454) – lifebalance

Trả lời

130

xây dựng một danh sách mới với một sự hiểu biết danh sách:

new_items = [x if x % 2 else None for x in items] 

Bạn có thể chỉnh sửa danh sách ban đầu tại chỗ nếu bạn muốn, nhưng nó không thực sự tiết kiệm thời gian:

items = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 
for index, item in enumerate(items): 
    if not (item % 2): 
     items[index] = None 

Dưới đây là thời gian (Python 3.6.3) biểu thị thời gian không được phép:

In [1]: %%timeit 
    ...: items = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 
    ...: for index, item in enumerate(items): 
    ...:  if not (item % 2): 
    ...:   items[index] = None 
    ...: 
1.06 µs ± 33.7 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) 

In [2]: %%timeit 
    ...: items = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 
    ...: new_items = [x if x % 2 else None for x in items] 
    ...: 
891 ns ± 13.6 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) 

Và Python 2.7.6 timings:

In [1]: %%timeit 
    ...: items = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 
    ...: for index, item in enumerate(items): 
    ...:  if not (item % 2): 
    ...:   items[index] = None 
    ...: 
1000000 loops, best of 3: 1.27 µs per loop 
In [2]: %%timeit 
    ...: items = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 
    ...: new_items = [x if x % 2 else None for x in items] 
    ...: 
1000000 loops, best of 3: 1.14 µs per loop 
+2

là hiệu quả nhất? không liệt kê phải tạo ra một iterator và tạo thành một bộ tuple, thêm chi phí? là danh sách trong mảng danh sách python, cho phép bạn truy cập thời gian không đổi? – geowa4

+0

Tôi nghĩ rằng, và tôi có thể sai, rằng ông có nghĩa là cho một bản sao của danh sách được trả lại thay vì sửa đổi bản gốc tại chỗ. Nhưng vẫn, +1 để cung cấp giải pháp hiệu quả khi sửa đổi tại chỗ được cho phép. –

+0

Nếu tôi muốn sửa đổi bản gốc tại chỗ, không phải nó cũng có thể sử dụng imap từ itertools? –

2
>>> L = range (11) 
>>> [ x if x%2 == 1 else None for x in L ] 
[None, 1, None, 3, None, 5, None, 7, None, 9, None] 
53
ls = [x if (condition) else None for x in ls] 
10

Riffing về một câu hỏi bên hỏi của OP trong một chú thích, ví dụ:

gì nếu tôi có một máy phát điện mà mang lại các giá trị từ dải ô (11) thay vì danh sách . Có thể thay thế các giá trị trong máy phát không?

Chắc chắn, đó là trivially dễ dàng ...:

def replaceiniter(it, predicate, replacement=None): 
    for item in it: 
    if predicate(item): yield replacement 
    else: yield item 

Chỉ cần vượt qua bất kỳ iterable (bao gồm cả các kết quả của cách gọi một máy phát điện) là arg đầu tiên, vị từ để quyết định xem một giá trị phải được thay thế như là arg thứ hai, và để cho 'er rip.

Ví dụ:

>>> list(replaceiniter(xrange(11), lambda x: x%2)) 
[0, None, 2, None, 4, None, 6, None, 8, None, 10] 
+0

+1 hehe ... tôi muốn tìm hiểu làm thế nào để viết này" một "dòng giải pháp trăn tiện lợi ... gợi ý xin – gath

+0

@ gath, tôi không hiểu câu hỏi của bạn - ý kiến ​​là khá hạn chế vì vậy bạn nên mở một câu hỏi mới để bạn có thể mở rộng và làm rõ những gì bạn đang tìm kiếm ... –

8

Dưới đây là một cách khác:

>>> L = range (11) 
>>> map(lambda x: x if x%2 else None, L) 
[None, 1, None, 3, None, 5, None, 7, None, 9, None] 
+1

+1 và làm thế nào để guys tìm hiểu này một dòng mã trăn tiện lợi ... gợi ý – gath

+5

@ gath: Don ' t khao khát viết một lớp lót cho mọi mục đích. Đôi khi, chúng tăng khả năng đọc hoặc hiệu suất, nhưng thường thì không. Theo gợi ý: Tìm hiểu các công cụ mà Python ofters, đặc biệt là danh sách (và cho Python 3 cũng dict) comprehensions, toán tử ternary, các hàm ẩn danh (lambda) và các hàm như map, zip, filter, reduce,… – balpha

2

này có thể giúp ...

test_list = [5, 8] 
test_list[0] = None 
print test_list 
#prints [None, 8] 
+1

bạn giải thích một số lý do tại sao bạn nghĩ rằng nó có thể giúp đỡ? –

+0

@ T-Heron Nó có thể được sửa đổi để đáp ứng những gì câu hỏi được yêu cầu cho – Emil

+0

Nếu nó cần phải được * sửa đổi *, sau đó nó không phải là một câu trả lời cho câu hỏi đó đang được yêu cầu. Vui lòng tự mình thực hiện (hoặc giải thích) các sửa đổi cần thiết, hoặc xóa câu trả lời. –

0

Trong trường hợp bạn muốn thay thế các giá trị tại chỗ, bạn có thể cập nhật danh sách ban đầu của bạn với các giá trị từ danh sách comprehensi bằng cách gán cho toàn bộ lát của bản gốc.

data = [*range(11)] # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 
id_before = id(data) 
data[:] = [x if x % 2 else None for x in data] 
data 
# Out: [None, 1, None, 3, None, 5, None, 7, None, 9, None] 
id_before == id(data) # check if list is still the same 
# Out: True 

Nếu bạn có nhiều tên trỏ đến danh sách ban đầu, ví dụ bạn đã viết data2=data trước khi thay đổi danh sách và bạn bỏ qua các ký hiệu slice cho gán cho data, data sẽ rebind để trỏ đến mới được tạo danh sách trong khi data2 vẫn trỏ đến danh sách không thay đổi ban đầu.

data = [*range(11)] # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 
data2 = data 
id_before = id(data) 
data = [x if x % 2 else None for x in data] # no [:] here 
data 
# Out: [None, 1, None, 3, None, 5, None, 7, None, 9, None] 
id_before == id(data) # check if list is still the same 
# Out: False 
data2 
# Out: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 

Lưu ý: Đây không phải là đề nghị cho thường thích một trong khác (thay đổi danh sách ở vị trí hay không), nhưng hành vi của bạn cần phải nhận thức.

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