簡體   English   中英

字典鍵的子集

[英]Subset of dictionary keys

我有一個形式為{'ip1:port1' : <value>, 'ip1:port2' : <value>, 'ip2:port1' : <value>, ...}的python字典。 字典鍵是字符串,由ip:端口對組成。 值對此任務並不重要。

我需要一個具有唯一IP地址的ip:port組合列表,端口可以是原始密鑰中出現的任何端口。 例如,上面可以接受兩種變體: ['ip1:port1', ip2:port1']['ip1:port2', ip2:port1']

這種方式最蟒蛇的方式是什么?

目前我的解決方案是

def get_uniq_worker_ips(workers):
    wip = set(w.split(':')[0] for w in workers.iterkeys())
    return [[worker for worker in workers.iterkeys() if worker.startswith(w)][0] for w in wip]

我不喜歡它,因為它創建了額外的列表然后丟棄它們。

您可以使用itertools.groupby按相同的IP地址分組:

data = {'ip1:port1' : "value1", 'ip1:port2' : "value2", 'ip2:port1' : "value3", 'ip2:port2': "value4"}
by_ip = {k: list(g) for k, g in itertools.groupby(sorted(data), key=lambda s: s.split(":")[0])}
by_ip
# {'ip1': ['ip1:port1', 'ip1:port2'], 'ip2': ['ip2:port1', 'ip2:port2']}

然后從不同的IP組中選擇任何一個。

{v[0]: data[v[0]] for v in by_ip.values()}
# {'ip1:port1': 'value1', 'ip2:port1': 'value3'}

或者更短,只為組中的第一個鍵生成一個生成器表達式:

one_by_ip = (next(g) for k, g in itertools.groupby(sorted(data), key=lambda s: s.split(":")[0]))
{key: data[key] for key in one_by_ip}
# {'ip1:port1': 'value1', 'ip2:port1': 'value3'}

但請注意, groupby要求對輸入數據進行排序。 因此,如果您想避免對dict中的所有鍵進行排序,則應該只使用一set已經看過的鍵。

seen = set()
not_seen = lambda x: not(x in seen or seen.add(x))
{key: data[key] for key in data if not_seen(key.split(":")[0])}
# {'ip1:port1': 'value1', 'ip2:port1': 'value3'}

這與您的解決方案類似,但不是循環使用唯一鍵並在每個dict中找到匹配鍵,而是循環鍵並檢查您是否已經看過IP。

實現此目的的一種方法是將密鑰轉換為自定義類,該類僅在執行相等性測試時查看字符串的IP部分。 它還需要提供適當的__hash__方法。

這里的邏輯是set構造函數將“看到”具有相同IP的密鑰相同,忽略比較中的端口部分,因此如果具有該IP的密鑰已存在於集合中,則將避免向該集合添加密鑰。

這是一些在Python 2或Python 3上運行的代碼。

class IPKey(object):
    def __init__(self, s):
        self.key = s
        self.ip, self.port = s.split(':', 1)

    def __eq__(self, other):
        return self.ip == other.ip

    def __hash__(self):
        return hash(self.ip)

    def __repr__(self):
        return 'IPKey({}:{})'.format(self.ip, self.port)

def get_uniq_worker_ips(workers):
    return [k.key for k in set(IPKey(k) for k in workers)]

# Test

workers = {
    'ip1:port1' : "val", 
    'ip1:port2' : "val", 
    'ip2:port1' : "val", 
    'ip2:port2' : "val", 
}

print(get_uniq_worker_ips(workers))    

產量

['ip2:port1', 'ip1:port1']

如果您運行的是Python 2.7或更高版本,則該函數可以使用set comprehension而不是set()構造函數調用中的該生成器表達式。

def get_uniq_worker_ips(workers):
    return [k.key for k in {IPKey(k) for k in workers}]

IPKey.__repr__方法並不是絕對必要的,但我喜歡給我所有的類__repr__因為它在開發過程中很方便。


這是一個更加簡潔的解決方案,非常有效,由Jon Clements提供 它通過字典理解構建所需的列表。

def get_uniq_worker_ips(workers):
    return list({k.partition(':')[0]:k for k in workers}.values())

我在我的解決方案中改變了幾個字符,現在對它感到滿意。

def get_uniq_worker_ips(workers):
    wip = set(w.split(':')[0] for w in workers.iterkeys())
    return [next(worker for worker in workers.iterkeys() if worker.startswith(w)) for w in wip]

感謝@Ignacio Vazquez-Abrams和@MT的解釋。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM