xóa Không có giá trị khỏi danh sách mà không xóa giá trị 0


244

Đây là nguồn của tôi, tôi bắt đầu với.

Danh sách của tôi

L = [0, 23, 234, 89, None, 0, 35, 9]

Khi tôi chạy này:

L = filter(None, L)

Tôi nhận được kết quả này

[23, 234, 89, 35, 9]

Nhưng đây không phải là thứ tôi cần, thứ tôi thực sự cần là:

[0, 23, 234, 89, 0, 35, 9]

Bởi vì tôi đang tính phần trăm dữ liệu và 0 tạo ra nhiều sự khác biệt.

Làm cách nào để xóa giá trị Không có trong danh sách mà không xóa giá trị 0?

Câu trả lời:


353
>>> L = [0, 23, 234, 89, None, 0, 35, 9]
>>> [x for x in L if x is not None]
[0, 23, 234, 89, 0, 35, 9]

Để giải trí, đây là cách bạn có thể thích nghi filterđể làm điều này mà không cần sử dụng lambda, (Tôi không khuyến nghị mã này - nó chỉ dành cho mục đích khoa học)

>>> from operator import is_not
>>> from functools import partial
>>> L = [0, 23, 234, 89, None, 0, 35, 9]
>>> filter(partial(is_not, None), L)
[0, 23, 234, 89, 0, 35, 9]

23
filterPhiên bản kém thanh lịch hơn : filter(lambda x: x is not None, L)- Bạn có thể thoát khỏi việc lambdasử dụng partialoperator.is_nottôi nghĩ, nhưng có lẽ nó không có giá trị vì danh sách comp là sạch hơn rất nhiều.
mgilson

3
@mgilson Oh wow tôi thậm chí không biết is_notđã tồn tại! Tôi nghĩ đó là duy nhất is_, tôi sẽ thêm nó chỉ để cho vui
jamylak

@jamylak - Vâng. Nó thực sự làm phiền tôi rằng is_nottồn tại và not_inkhông tồn tại. Tôi thực sự nghĩ rằng not_innên biến nó thành một phương pháp ma thuật __not_contains__... xem một câu hỏi tôi đã hỏi một lúc trước và một nhận xét tôi đã đưa ra cho một người trả lời ... và vẫn không cảm thấy như nó đã được giải quyết.
mgilson

@mgilson Tôi nghĩ theo giả định tương tự, tôi chỉ cho rằng nó không tồn tại. Tôi đoán bạn chỉ có thể sử dụng filterfalsehoặc một cái gì đó tùy thuộc vào trường hợp sử dụng
jamylak

@jamylak - Vâng. Vấn đề chính của tôi là điều x > yđó không bao hàm not x <= ytrong python bởi vì bạn có thể làm bất cứ điều gì trong __lt____le__vậy, tại sao lại phải x not in yngụ ý not x in y(đặc biệt là vì not innó có mã byte riêng?)
mgilson

136

FWIW, Python 3 làm cho vấn đề này trở nên dễ dàng:

>>> L = [0, 23, 234, 89, None, 0, 35, 9]
>>> list(filter(None.__ne__, L))
[0, 23, 234, 89, 0, 35, 9]

Trong Python 2, bạn sẽ sử dụng cách hiểu danh sách thay thế:

>>> [x for x in L if x is not None]
[0, 23, 234, 89, 0, 35, 9]

+1 Bạn có đề nghị sử dụng __ne__như thế trái ngược với partialnekhông?
jamylak

1
@jamylak Vâng, nó nhanh hơn, dễ viết hơn một chút và rõ ràng hơn một chút.
Raymond Hettinger

Cân nhắc sử dụng operatormô-đun.
đúng vào

12
__ne__
DrMcCleod

11
@DrMcCleod Biểu thức x != ygọi nội bộ trong x.__ne__(y)đó ne là viết tắt của "không bằng". Vì vậy, None.__ne__là một phương thức ràng buộc trả về True khi được gọi với bất kỳ giá trị nào khác ngoài Không có . Ví dụ, bm = None.__ne__gọi với bm(10)lợi nhuận NotImplemented mà như giá trị thực sự, và bm(None)trở về False .
Raymond Hettinger

16

Đối với Python 2.7 (Xem câu trả lời của Raymond, tương đương với Python 3):

Muốn biết liệu cái gì đó "không phải là Không" rất phổ biến trong python (và các ngôn ngữ OO khác), trong Common.txt của tôi (mà tôi nhập vào từng mô-đun bằng "từ Nhập chung *"), tôi bao gồm các dòng sau:

def exists(it):
    return (it is not None)

Sau đó, để xóa Không có phần tử nào khỏi danh sách, chỉ cần thực hiện:

filter(exists, L)

Tôi thấy điều này dễ đọc hơn so với việc hiểu danh sách tương ứng (mà Raymond thể hiện, như phiên bản Python 2 của anh ấy).


Tôi thích giải pháp Raymonds cho Python 3, và sau đó là phần hiểu danh sách cho Python 2. Nhưng nếu tôi phải đi theo con đường này, tôi sẽ thích partial(is_not, None)giải pháp này hơn. Tôi tin rằng điều này sẽ chậm hơn (mặc dù điều đó không quá quan trọng). Nhưng với một vài lần nhập các mô-đun python, không cần một chức năng được xác định tùy chỉnh trong trường hợp này
jamylak

16

Sử dụng hiểu danh sách này có thể được thực hiện như sau:

l = [i for i in my_list if i is not None]

Giá trị của l là:

[0, 23, 234, 89, 0, 35, 9]

Giải pháp này đã được tìm thấy trong câu trả lời hàng đầu, hoặc tôi đang thiếu một cái gì đó?
Qaswed

12

Câu trả lời @jamylak khá hay, tuy nhiên nếu bạn không muốn nhập một vài mô-đun chỉ để thực hiện công việc đơn giản này, hãy viết lambdatại chỗ:

>>> L = [0, 23, 234, 89, None, 0, 35, 9]
>>> filter(lambda v: v is not None, L)
[0, 23, 234, 89, 0, 35, 9]

Rõ ràng là bạn đã không đọc chính xác giải pháp của tôi, đó là [x for x in L if x is not None]mã khác chỉ là một bổ sung mà tôi đã tuyên bố rõ ràng tôi không khuyến nghị
jamylak

1
@jamylak - Tôi đã đọc nó, nhưng bạn đã không bao gồm giải pháp này. - Cũng không chắc chắn lý do tại sao bạn chỉnh sửa câu trả lời của mọi người từ 4-5 năm trước.
TẠI

5

Lặp lại so với không gian , việc sử dụng có thể là một vấn đề. Trong các tình huống khác nhau, hồ sơ có thể hiển thị hoặc là "nhanh hơn" và / hoặc "ít bộ nhớ" hơn.

# first
>>> L = [0, 23, 234, 89, None, 0, 35, 9, ...]
>>> [x for x in L if x is not None]
[0, 23, 234, 89, 0, 35, 9, ...]

# second
>>> L = [0, 23, 234, 89, None, 0, 35, 9]
>>> for i in range(L.count(None)): L.remove(None)
[0, 23, 234, 89, 0, 35, 9, ...]

Cách tiếp cận đầu tiên (cũng được đề xuất bởi @jamylak , @Raymond Hettinger@Dipto ) tạo ra một danh sách trùng lặp trong bộ nhớ, có thể tốn kém cho một danh sách lớn với một vài Nonemục.

Cách tiếp cận thứ hai đi qua danh sách một lần, và sau đó một lần nữa cho đến khi Noneđạt được a. Điều này có thể ít bộ nhớ hơn và danh sách sẽ nhỏ hơn khi nó đi. Việc giảm kích thước danh sách có thể tăng tốc cho rất nhiều Nonemục ở phía trước, nhưng trường hợp xấu nhất sẽ xảy ra nếu có nhiều Nonemục ở phía sau.

Các kỹ thuật song song và tại chỗ là các cách tiếp cận khác, nhưng mỗi phương pháp đều có các biến chứng riêng trong Python. Biết dữ liệu và các trường hợp sử dụng thời gian chạy, cũng như cấu hình chương trình là nơi bắt đầu cho các hoạt động chuyên sâu hoặc dữ liệu lớn.

Chọn một trong hai cách tiếp cận có thể sẽ không quan trọng trong các tình huống phổ biến. Nó trở thành một ưu tiên của ký hiệu. Trong thực tế, trong những trường hợp không phổ biến đó, numpyhoặc cythoncó thể là những lựa chọn thay thế đáng giá thay vì cố gắng tối ưu hóa vi mô Python.


Không phải là một fan hâm mộ của điều này, toàn bộ lợi thế bạn yêu cầu với giải pháp này là danh sách có thể rất lớn đến nỗi việc xây dựng danh sách trùng lặp trong bộ nhớ có thể tốn kém. Vậy thì giải pháp của bạn sẽ còn tốn kém hơn vì bạn đang quét toàn bộ danh sách L.count(None)và sau đó bạn gọi .remove(None)nhiều lần khiến O(N^2)tình huống này bạn đang cố gắng giải quyết không nên xử lý theo cách này, dữ liệu nên được cơ cấu lại vào một cơ sở dữ liệu hoặc tập tin thay vào đó nếu nó chiếm nhiều bộ nhớ.
jamylak

@jamylak Đúng, nhưng không phải tất cả các tình huống hoặc dữ liệu trong thế giới thực đều cho phép sự linh hoạt đó. Ví dụ: bơm dữ liệu không gian địa lý "di sản" thông qua phân tích một lần trên hệ thống mà không cần nhiều bộ nhớ. Sau đó cũng có thời gian lập trình so với thời gian chạy để xem xét. Mọi người thường chuyển sang Python vì tiết kiệm thời gian phát triển. Với câu trả lời này, tôi đang chú ý đến thực tế rằng bộ nhớ có thể đáng xem xét, nhưng cuối cùng tôi nói rằng đó chủ yếu là sở thích cá nhân trong ký hiệu. Tôi cũng chỉ ra rằng việc biết dữ liệu là quan trọng. O(n^2)chỉ khi toàn bộ danh sách là None.
Kevin

Sẽ có hứng thú nếu bạn có một ví dụ thực tế trong đó câu trả lời này là giải pháp tốt nhất, tôi có xu hướng nghĩ rằng sẽ có một cách tiếp cận tốt hơn trong mọi trường hợp. Ví dụ: numpycó thể xử lý loại hoạt động này theo cách tối ưu hơn
jamylak

@jamylak Để công bằng, tôi đã sử dụng numpytrong những năm gần đây, nhưng nó là một kỹ năng riêng biệt. Nếu Lđược khởi tạo như một numpy.arraythay vì Python list, thì L = L[L != numpy.array(None)](stackoverflow.com/a/25255015/3003133) có lẽ tốt hơn một trong hai, nhưng tôi không biết chi tiết triển khai để xử lý so với bộ nhớ bên dưới. Nó ít nhất tạo ra một mảng booleans dài cho mặt nạ. Cú pháp so sánh bên trong toán tử truy cập (chỉ mục), theo cách đó, là mới đối với tôi. Cuộc thảo luận này cũng đã làm tôi chú ý dtype=object.
Kevin

Cuộc thảo luận này đang trở nên quá trừu tượng, tôi không nghĩ rằng bạn có thể đưa cho tôi một ví dụ thực tế trong nhiều năm kinh nghiệm của bạn khi câu trả lời này là cách tiếp cận chính xác trong việc tái cấu trúc dữ liệu như tôi đã đề cập trước đây.
jamylak

2
from operator import is_not
from functools import partial   

filter_null = partial(filter, partial(is_not, None))

# A test case
L = [1, None, 2, None, 3]
L = list(filter_null(L))

6
Xin vui lòng, cung cấp một số thông tin chi tiết cho OP, và không chỉ là một mã.
Laurent LAPORTE

1
Tôi đã làm. Bạn nghĩ gì?
med_abidi

Chà, điều này không trả lời câu hỏi OP. Thay vào đó, hãy xem xét câu trả lời này: stackoverflow.com/a/16096769/1513933
Laurent LAPORTE

Có bạn đúng. Có một vấn đề với bộ lọc một phần.
med_abidi

2

Nếu đó là tất cả danh sách các danh sách, bạn có thể sửa đổi câu trả lời của ngài @ Raymond

L = [ [None], [123], [None], [151] ] no_none_val = list(filter(None.__ne__, [x[0] for x in L] ) ) cho python 2 tuy nhiên

no_none_val = [x[0] for x in L if x[0] is not None] """ Both returns [123, 151]"""

<< list_indice [0] cho biến trong Danh sách nếu biến không phải là Không >>


1

Nói danh sách như dưới đây

iterator = [None, 1, 2, 0, '', None, False, {}, (), []]

Điều này sẽ chỉ trả lại những mặt hàng mà bool(item) is True

print filter(lambda item: item, iterator)
# [1, 2]

Điều này tương đương với

print [item for item in iterator if item]

Để chỉ lọc Không:

print filter(lambda item: item is not None, iterator)
# [1, 2, 0, '', False, {}, (), []]

Tương đương với:

print [item for item in iterator if item is not None]

Để có được tất cả các mục đánh giá thành Sai

print filter(lambda item: not item, iterator)
# Will print [None, '', 0, None, False, {}, (), []]
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.