我有一个python中的对象列表,以及一个比较函数,给定两个对象,决定它们是否应该被认为是相等的。
我想将对象列表转换为新的列表列表,其中每个子列表都会收集比较相等的元素。
这是一种pythonic方式吗?
答案 0 :(得分:2)
拥有compare
函数,根据元素是否相等而返回True
或False
并不理想。基本上,您必须将每个元素与每个现有组中的一些“原型”进行比较。像这样:
def group(elements, comp_func):
groups = {}
for x in elements:
for y in groups:
if comp_func(x, y):
groups[y].append(x)
break
else:
groups[x] = [x]
return groups
或者更短(但不是更快):
def group(elements, comp_func):
groups = {}
for x in elements:
prototype = next((y for y in groups if comp_func(x, y)), x)
groups.setdefault(prototype, []).append(x)
return groups
示例:
>>> def comp_len(o1, o2):
... return len(o1) == len(o2)
>>> group(["foo", "bar", "blub", "blah", "bonk"], comp_len)
{'foo': ['foo', 'bar'], 'blub': ['blub', 'blah', 'bonk']}
使用key
函数,将每个元素映射到某个hashable值会更好:
def group(elements, key_func):
groups = {}
for x in elements:
key = key_func(x)
if key in groups:
groups[key].append(x)
else:
groups[key] = [x]
return groups
示例:
>>> group(["foo", "bar", "blub", "blah", "bonk"], len)
{3: ['foo', 'bar'], 4: ['blub', 'blah', 'bonk']}
答案 1 :(得分:2)
一种方法是使用现成的集合合并算法(无论如何它经常出现在你的工具箱中),只需使用你的awk -vOFS="\t" 'NR==1{$1="Time";$2=""} {print $1,$2,$9}'
函数将数据输入其中。也就是说,我们将其视为集合/连接组件问题,其中每个对象都是一个节点,compare
表示节点之间存在边缘。
N.B。我假设传递性,compare(x,y) == True
暗示compare(x,y) and compare(x,z)
。如果那不是真的,那就是你自己。 : - )
具体:
compare(y,z)
给出了
from itertools import combinations
def consolidate(sets):
# http://rosettacode.org/wiki/Set_consolidation#Python:_Iterative
setlist = [s for s in sets if s]
for i, s1 in enumerate(setlist):
if s1:
for s2 in setlist[i+1:]:
intersection = s1.intersection(s2)
if intersection:
s2.update(s1)
s1.clear()
s1 = s2
return [s for s in setlist if s]
def groupify(seq, comp_func):
nodes = [{x} for x in seq]
edges = [{x,y} for x,y in combinations(seq,2) if comp_func(x,y)]
return [list(g) for g in consolidate(nodes + edges)]
不可否认,这并非超级简洁,但请记住,对于我来说,>>> def compare(x,y): return max(x)==max(y)
>>> res = groupify(["aaa","abc","a","cab","e","eaab","h"], compare)
>>> res
[['h'], ['a', 'aaa'], ['cab', 'abc'], ['eaab', 'e']]
只是我在这一点上导入的东西(因为它非常方便),所以从我的角度来看,这只需要几行。 / p>