2012-06-22 22 views
5

phép nói rằng tôi có một danh sách:Python: Uniquefying một danh sách với một twist

L = [15,16,57,59,14] 

Danh sách chứa mesurements, mà không phải là rất chính xác: đó là giá trị thực của một phần tử là + -2 của giá trị ghi lại. Vì vậy, 14,15 và 16 có thể có cùng giá trị. Những gì tôi muốn làm là để uniquefy danh sách đó, có tính đến các lỗi mesurement. Sản lượng nên do là:

l_out = [15,57] 

hoặc

l_out = [(14,15,16),(57,59)] 

Tôi không có vấn đề sản xuất một trong hai kết quả với một vòng lặp for. Tuy nhiên, tôi tò mò nếu có thể có một giải pháp thanh lịch hơn. Ý tưởng được đánh giá cao.

+5

Bạn mong đợi kết quả gì cho 'L = [1,2,3,4,5,6,7,8,10]'? – sloth

+0

Và đầu ra của [15,16,57,59,14,13] là bao nhiêu? – kosii

+0

Tôi biết vấn đề, nhưng dữ liệu mà tôi có trong tâm trí được sờ mó để khoảng cách giữa các nhóm là> 2 – root

Trả lời

5

Như lazyr chỉ ra trong các ý kiến , một vấn đề tương tự đã được đăng here. Sử dụng các module cụm giải pháp cho vấn đề của tôi sẽ là:

>>> from cluster import * 
>>> L = [15,16,57,59,14] 
>>> cl = HierarchicalClustering(L, lambda x,y: abs(x-y)) 
>>> cl.getlevel(2) 
[[14, 15, 16], [57, 59]] 

hoặc (để có được danh sách độc đáo với giá trị trung bình của mỗi nhóm):

>>> [mean(cluster) for cluster in cl.getlevel(2)] 
[15, 58] 
-1

Đối với vòng lặp là cách đơn giản nhất, nhưng nếu bạn thực sự muốn có một mã duy nhất-line:
l_out = list(set(tuple([tuple(filter(lambda i: abs(item - i) < 3, L)) for item in L])))
Rất rõ ràng, mặc dù tôi muốn cho phiên bản :)

+2

Điều này sẽ không hoạt động cho ví dụ '[15,16,57,59,14,13] ' –

+0

anh ấy nói" Tôi biết vấn đề, nhưng dữ liệu mà tôi có trong tâm trí được sờ mó để khoảng cách giữa các nhóm là> 2 " – lolopop

+1

điều kiện đó được đáp ứng ở đây. vẫn chương trình của bạn không phân vùng danh sách đúng cách. –

2

Nếu bạn muốn chuẩn python lib, itertool 's groupby là bạn của bạn:

from itertools import groupby 

L = [15,16,57,59,14] 

# Stash state outside key function. (a little hacky). 
# Better way would be to create stateful class with a __call__ key fn. 
state = {'group': 0, 'prev': None} 
thresh = 2 

def _group(cur): 
    """Group if within threshold.""" 
    if state["prev"] is not None and abs(state["prev"] - cur) > thresh: 
     state["group"] += 1 # Advance group 
    state["prev"] = cur 
    return state["group"] 

# Group, then drop the group key and inflate the final tuples. 
l_out = [tuple(g) for _, g in groupby(sorted(L), key=_group)] 

print l_out 
# -> [(14, 15, 16), (57, 59)] 
+0

@ +1 Ryan không tệ :) – root

+0

Tôi nghĩ bạn có thể tránh trạng thái toàn cầu bằng cách nhóm các giá trị thành các cặp đầu tiên thông qua 'l = được sắp xếp (L); zip (l, l [1:]) ' –

+0

@NiklasB. -- Vâng! Một cách khác sẽ là một kiểu trang trí cổ điển-phân loại trang trí cổ điển hơn ... Hoặc tôi đoán kiểu trang trí-nhóm-undecorate;) –

2

đây là cách tôi muốn làm điều này trong một cách tiếp cận thuần Python:

s = sorted(L) 
b = [i + 1 for i, (x, y) in enumerate(zip(s, s[1:])) if y > x + 2] 
result = [s[i:j] for i, j in zip([None] + b, b + [None])] 

Ở đây b là danh sách "ngắt", chỉ mục nơi cụm kết thúc.

+0

@NiklasB. cảm ơn, lỗi off-by-one; đã sửa. – ecatmur

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