扩展分组代码以处理更多常规输入

时间:2014-06-12 18:54:21

标签: python list

我需要根据键是大于还是小于给定值,将浮点列表或不同长度的(命名)元组列表分组。

例如,给定一个小于1的2的幂列表,以及一个截止列表:

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

如何通过添加默认为浮点数(或整数等)的键来扩展原始方法,但是可以处理元组和命名元组的键?

例如:

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

1 个答案:

答案 0 :(得分:1)

在我的回答中,我假设,截止日期以递增顺序结束 - 只是为了简化情况。

Discriminator检测到一个插槽

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函数,但是我把它从这个答案中删除了,因为它变得太长了。

相关问题