我需要根据键是否大于或小于给定值将 float 列表或不同长度的(命名)元组列表分组。
例如,给定一个 2 小于 1 的幂列表,以及一个截止列表:
twos = [2**(-(i+1)) for i in range(0,10)]
cutoffs = [0.5, 0.125, 0.03125]
然后函数
split_into_groups(twos, cutoffs)
应该返回
[[0.5], [0.25, 0.125], [0.0625, 0.03125], [0.015625, 0.0078125, 0.00390625, 0.001953125, 0.0009765625]]
我实现了这样的功能:
def split_by_prob(items, cutoff, groups, key=None):
for k,g in groupby(enumerate(items), lambda (j,x): x<cutoff):
groups.append((map(itemgetter(1),g)))
return groups
def split_into_groups(items, cutoffs, key=None):
groups = items
final = []
for i in cutoffs:
groups = split_by_prob(groups,i,[],key)
if len(groups) > 1:
final.append(groups[0])
groups = groups.pop()
else:
final.append(groups[0])
return final
final.append(groups)
return final
目前通过的测试是:
>>> split_by_prob(twos, 0.5, [])
[[0.5], [0.25, 0.125, 0.0625, 0.03125, 0.015625, 0.0078125, 0.00390625, 0.001953125, 0.0009765625]]
>>> split_into_groups(twos, cutoffs)
[[0.5], [0.25, 0.125], [0.0625, 0.03125], [0.015625, 0.0078125, 0.00390625, 0.001953125, 0.0009765625]]
>>> split_into_groups(twos, cutoffs_p10)
[[0.5, 0.25, 0.125], [0.0625, 0.03125, 0.015625], [0.0078125, 0.00390625, 0.001953125], [0.0009765625]]
其中 cutoffs_p10 = [10**(-(i+1)) for i in range(0,5)]
我可以直接将其扩展为以下形式的元组列表
items = zip(range(0,10), twos)
通过改变
def split_by_prob(items, cutoff, groups, key=None):
for k,g in groupby(enumerate(items), lambda (j,x): x<cutoff):
groups.append((map(itemgetter(1),g)))
return groups
到
def split_by_prob(items, cutoff, groups, key=None):
for k,g in groupby(enumerate(items), lambda (j,x): x[1]<cutoff):
groups.append((map(itemgetter(1),g)))
return groups
如何通过添加一个默认为 float (或整数等)列表但可以处理元组和命名元组的键来扩展原始方法?
例如:
split_into_groups(items, cutoffs, key=items[0])
会返回
[[(0,0.5)], [(1,0.25), (2,0.125)], [(3,0.0625), (4,0.03125)], [(5,0.015625), (6,0.0078125), (7,0.00390625), (8,0.001953125), (9,0.0009765625)]]
最佳答案
在我的回答中,我认为截止值是按递增顺序排列在最后 - 只是为了简化情况。
鉴别器
检测槽
class Discriminator(object):
def __init__(self, cutoffs):
self.cutoffs = sorted(cutoffs)
self.maxslot = len(cutoffs)
def findslot(self, num):
cutoffs = self.cutoffs
for slot, edge in enumerate(self.cutoffs):
if num < edge:
return slot
return self.maxslot
grouper
将元素放入插槽
from collections import defaultdict
def grouper(cutoffs, items, key=None):
if not key:
key = lambda itm: itm
discr = Discriminator(cutoffs)
result = defaultdict(list)
for item in items:
num = key(item)
result[discr.findslot(num)].append(item)
return result
def split_into_groups(cutoffs, numbers, key=None):
groups = grouper(cutoffs, numbers, key)
slot_ids = sorted(groups.keys())
return [groups[slot_id] for slot_id in slot_ids]
关于判别器和grouper
的结论
建议的鉴别器甚至适用于未排序的项目。
关于key
的结论
事实上,提供key
功能比最初看起来更容易。
它只是一个通过参数提供的函数,因此它成为调用转换函数来获取值的别名,我们想用它来进行比较、分组等。
有一种特殊情况None
,对于这种情况我们必须使用一些恒等函数。
最简单的是
func = lambda itm: itm
注意:上面的所有功能都通过测试套件进行了测试(包括使用 key
功能,但我从这个答案中删除了它,因为它变得太长了。
关于python - 扩展分组代码以处理更通用的输入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24191889/