python - 扩展分组代码以处理更通用的输入

标签 python list

我需要根据键是否大于或小于给定值将 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/

相关文章:

python - pip install pkg 给出权限被拒绝 :/Library/Python/2. 7/site-packages/pkg

Python:Dennis Nedry - 安全

python - 清理打印命令

c# - 比较列表中的日期时间元素 C#

python - Pandas 列表列,为每个列表元素创建一行

python - GUI提供的评估公式

php - 在php代码中用python导入caffe

python - 如果只输入了列表中单词的一部分,我的代码会检查它是否为真,并且部分单词在列表中

list - 删除列表中给定元素的第一次出现

同一列表中的 Python ID 不相等