字典键的子集

2024-03-29 09:44:28 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个格式为{'ip1:port1' : <value>, 'ip1:port2' : <value>, 'ip2:port1' : <value>, ...}的python字典。字典键是由ip:port对组成的字符串。值对于此任务不重要。

我需要一个具有唯一IP地址的ip:port组合的列表,端口可以是原始密钥中出现的任何端口。例如,可以接受两个变体:['ip1:port1', ip2:port1']和{}。

最像Python的方式是什么?

目前我的解决方案是

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]

我不喜欢它,因为它会创建额外的列表,然后丢弃它们。


Tags: 端口inip列表for字典valueport
3条回答

您可以使用^{}按相同的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。在

^{pr2}$

或者更短,为组中的第一个键生成生成器表达式:

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。在

在我的解决方案中,我改变了几个字符,现在对它很满意。在

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和@M.T.的解释。在

一种方法是将密钥转换为自定义类,该类在执行相等测试时只查看字符串的IP部分。它还需要提供适当的__hash__方法。在

这里的逻辑是set构造函数将“看到”具有相同IP的密钥,而忽略比较中的端口部分,因此如果集合中已经存在具有该IP的密钥,则它将避免向集合添加密钥。在

下面是一些在Python2或Python3上运行的代码。在

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))    

输出

^{pr2}$

如果运行的是Python2.7或更高版本,则函数可以使用集合理解,而不是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())

相关问题 更多 >