【问题标题】:How to group approximately adjacent list如何对近似相邻的列表进行分组
【发布时间】:2021-11-25 08:22:58
【问题描述】:

我有一个大致相邻的列表。

x=[10,11,13,70,71,73,170,171,172,174]

我需要将其分成具有最小偏差的列表(即)

y=[[10,11,13],[70,71,73],[170,171,172,174]]

您可以在 y 列表中看到分组为 3 个单独的列表,并在遇到巨大偏差时打破此列表。 你能给我一个提示或任何资源来解决这个问题吗?

【问题讨论】:

  • 遍历x。跟踪上次看到的元素和当前元素。查找当前元素是否在前一个元素之上的deviation。如果是,请将其添加到子列表中。如果没有,新的子列表。

标签: python list iteration


【解决方案1】:

当您需要将列表中的项目与其后继或前任进行比较时,zip 功能是您的朋友:

x=[10,11,13,70,71,73,170,171,172,174]

threshold = 50
breaks    = [i for i,(a,b) in enumerate(zip(x,x[1:]),1) if b-a>threshold]
groups    = [x[s:e] for s,e in zip([0]+breaks,breaks+[None])]

print(groups)
[[10, 11, 13], [70, 71, 73], [170, 171, 172, 174]]
  • breaks 将包含元素 (b) 的索引 (i),这些元素 (b) 比其前任 (a) 大超过 treshold 值。
  • 再次使用 zip() 可以将这些中断索引配对以形成开始/结束范围,您可以将其应用于原始列表以获取分组。

请注意,我使用固定阈值来检测“巨大”偏差,但您可以使用百分比或您选择的任何公式/条件来代替 if b-a>threshold。如果偏差计算很复杂,您可能需要创建一个 deviates() 函数并在列表推导中使用它:if deviates(a,b) 以便它保持可理解

如果 zip() 和列表推导太高级,您可以使用简单的 for 循环来做同样的事情:

def deviates(a,b):  # example of a (huge) deviation detection function
    return b-a > 50  

groups   = []   # resulting list of groups
previous = None # track previous number for comparison
for number in x:
    if not groups or deviates(previous, number): 
        groups.append([number])   # 1st item or deviation, add new group 
    else:
        groups[-1].append(number) # approximately adjacent, add to last group
    previous = number             # remember previous value for next loop

【讨论】:

  • 也许在 deviate() 函数中可以添加第三个参数作为间隙,以避免硬编码并保持灵活性。两者都喜欢。
【解决方案2】:

这样的事情应该可以解决问题:

test_list = [10, 11, 13, 70, 71, 73, 170, 171, 172, 174]


def group_approximately_adjacent(numbers):
    if not numbers:
        return []

    current_number = numbers.pop(0)
    cluster = [current_number]
    clusters = [cluster]

    while numbers:
        next_number = numbers.pop(0)
        if is_approximately_adjacent(current_number, next_number):
            cluster.append(next_number)
        else:
            cluster = [next_number]
            clusters.append(cluster)
        current_number = next_number

    return clusters


def is_approximately_adjacent(a, b):
    deviation = 0.25
    return abs(a * (1 + deviation)) > abs(b) > abs(a * (1 - deviation))

【讨论】:

  • 我建议在函数的开头复制一份列表,这样它就不会破坏输入(这可能会干扰调用代码的逻辑)。
猜你喜欢
  • 2015-02-23
  • 2014-03-15
  • 1970-01-01
  • 2010-10-03
  • 2019-09-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-26
相关资源
最近更新 更多