Python 基于缺失值从序列生成范围

Python 基于缺失值从序列生成范围,python,python-3.x,Python,Python 3.x,给定一个范围,范围101,我知道序列中缺少输入 { 8, 23, 56 } 在此范围内,唯一有效的数字是开始和结束,0和100。以下是我的初始化过程: r = tuple(range(101)) init_start, init_end = r[0], r[-1] missing = { 8, 23, 56 } r = tuple(filter(lambda n: n not in missing, r)) 这就是我被卡住的地方。我不知道如何生成孔所在的子范围。这里的预期输出是0、7、9、

给定一个范围,范围101,我知道序列中缺少输入

{ 8, 23, 56 }
在此范围内,唯一有效的数字是开始和结束,0和100。以下是我的初始化过程:

r = tuple(range(101))
init_start, init_end = r[0], r[-1]

missing = { 8, 23, 56 }
r = tuple(filter(lambda n: n not in missing, r))
这就是我被卡住的地方。我不知道如何生成孔所在的子范围。这里的预期输出是0、7、9、22、24、55和57100。我可以用已知的缺失值强制它,但它不能处理边缘情况,如果我在范围内只有一个值会怎么样

编辑 有人发布了一个解决问题的有效方案,但它忽略了边缘案例:

def gen_ranges(start, end, missing):
  missing = sorted(missing + [start - 1, end + 1])

  for num, value in enumerate(missing):
    if value - missing[num - 1] > 1:
      yield missing[num - 1] + 1
      yield value - 1

print(list(gen_ranges(0, 100, [8, 23, 56])))          # [0, 7, 9, 22, 24, 55, 57, 100]

print(list(gen_ranges(0, 100, [5, 40, 50, 52, 93])))  # [0, 4, 6, 39, 41, 49, 51, 51, 53, 92, 94, 100]

print(list(gen_ranges(0, 100, [0, 50, 100])))         # [1, 49, 51, 99]

print(list(gen_ranges(0, 100, [0, 50, 51, 100])))     # [1, 49, 52, 99]
如何处理顺序缺失的值? 如果起点或终点在缺少的值中,该怎么办?
我看到了几个问题:

您需要确保missing中的值已排序; 在处理完missing中的值后,您不会输出最后一对值 这应该会给出您想要的结果注意,我添加了missing作为一个参数,以简化测试:

def gen_ranges(missing):
    start = init_start
    end = 0

    for n in sorted(missing):
        if n == start:
            start = n + 1
            continue
        yield start
        start = n + 1

        end = n - 1
        yield end

    if start <= init_end:
        yield start
        yield init_end

print(list(gen_ranges({ 8,  9, 56 })))
print(list(gen_ranges({ 0 })))
print(list(gen_ranges({ 100 })))
print(list(gen_ranges({ 0, 100 })))
print(list(gen_ranges({ 1, 100 })))
print(list(gen_ranges({ 0, 99 })))
print(list(gen_ranges({ 0, 50, 100 })))
print(list(gen_ranges({ 0, 1, 50, 99, 100 })))

我看到了几个问题:

您需要确保missing中的值已排序; 在处理完missing中的值后,您不会输出最后一对值 这应该会给出您想要的结果注意,我添加了missing作为一个参数,以简化测试:

def gen_ranges(missing):
    start = init_start
    end = 0

    for n in sorted(missing):
        if n == start:
            start = n + 1
            continue
        yield start
        start = n + 1

        end = n - 1
        yield end

    if start <= init_end:
        yield start
        yield init_end

print(list(gen_ranges({ 8,  9, 56 })))
print(list(gen_ranges({ 0 })))
print(list(gen_ranges({ 100 })))
print(list(gen_ranges({ 0, 100 })))
print(list(gen_ranges({ 1, 100 })))
print(list(gen_ranges({ 0, 99 })))
print(list(gen_ranges({ 0, 50, 100 })))
print(list(gen_ranges({ 0, 1, 50, 99, 100 })))
使用itertools.groupby的一个解决方案:

印刷品:

[0, 7, 9, 22, 24, 55, 57, 100]
其他投入:

holes = {8, 10, 56}  # [0, 7, 9, 9, 11, 55, 57, 100]
holes = {8, 9, 56}   # [0, 7, 10, 55, 57, 100]
编辑一些解释:

我正在使用键功能从范围生成器创建组。以下是孔k中的关键函数k,k是范围中的值。如果键函数返回的值更改,则表示一个连续组。我基本上是这样做的:

False [0, 1, 2, ... 5, 6, 7]  # group 1 (Take first, last)
True [8, 9]                   # group 2
False [10, 11, ... 54, 55]    # group 3 (Take first, last)
True [56]                     # group 4
False [57, 58, ... 99, 100]   # group 5 (Take first, last)
使用itertools.groupby的一个解决方案:

印刷品:

[0, 7, 9, 22, 24, 55, 57, 100]
其他投入:

holes = {8, 10, 56}  # [0, 7, 9, 9, 11, 55, 57, 100]
holes = {8, 9, 56}   # [0, 7, 10, 55, 57, 100]
编辑一些解释:

我正在使用键功能从范围生成器创建组。以下是孔k中的关键函数k,k是范围中的值。如果键函数返回的值更改,则表示一个连续组。我基本上是这样做的:

False [0, 1, 2, ... 5, 6, 7]  # group 1 (Take first, last)
True [8, 9]                   # group 2
False [10, 11, ... 54, 55]    # group 3 (Take first, last)
True [56]                     # group 4
False [57, 58, ... 99, 100]   # group 5 (Take first, last)

已经有一个很好的公认答案,但这是一个有趣的问题

以下是我的解决方案,它适用于边缘情况:

def gen_ranges(start, end, missing):
  missing = sorted(missing + [start - 1, end + 1])

  for num, value in enumerate(missing):
    if value - missing[num - 1] > 1:
      yield missing[num - 1] + 1
      yield value - 1

print(list(gen_ranges(0, 100, [8, 23, 56])))          # [0, 7, 9, 22, 24, 55, 57, 100]

print(list(gen_ranges(0, 100, [5, 40, 50, 52, 93])))  # [0, 4, 6, 39, 41, 49, 51, 51, 53, 92, 94, 100]

print(list(gen_ranges(0, 100, [0, 50, 100])))         # [1, 49, 51, 99]

print(list(gen_ranges(0, 100, [0, 50, 51, 100])))     # [1, 49, 52, 99]

已经有一个很好的公认答案,但这是一个有趣的问题

以下是我的解决方案,它适用于边缘情况:

def gen_ranges(start, end, missing):
  missing = sorted(missing + [start - 1, end + 1])

  for num, value in enumerate(missing):
    if value - missing[num - 1] > 1:
      yield missing[num - 1] + 1
      yield value - 1

print(list(gen_ranges(0, 100, [8, 23, 56])))          # [0, 7, 9, 22, 24, 55, 57, 100]

print(list(gen_ranges(0, 100, [5, 40, 50, 52, 93])))  # [0, 4, 6, 39, 41, 49, 51, 51, 53, 92, 94, 100]

print(list(gen_ranges(0, 100, [0, 50, 100])))         # [1, 49, 51, 99]

print(list(gen_ranges(0, 100, [0, 50, 51, 100])))     # [1, 49, 52, 99]

不太清楚什么是输入,什么是您尝试的一部分。@HeapOverflow输入是范围元组的开始、结束,以及该范围中哪些值作为列表丢失。todo正在围绕丢失的值生成子范围。不太清楚什么是输入,什么是您尝试的一部分。@HeapOverflow输入是范围元组的开始、结束,以及该范围中哪些值作为列表丢失。todo正在围绕缺少的值生成子范围;有趣的我实际使用的数据是以列表的形式提供的,因此我会记住已排序的注释。我应该如何处理开始/结束可能是缺失片段的边缘情况?对于缺失={8,9,56}或缺失={8,10,56}似乎不起作用。@RickHitchcock是的,在这种情况下,它应该生成9,9,它确实为{8,10,56}生成了9,9,@TheIncorrigible1它应该为{8,9,56}生成什么?这是另一种边缘情况:missing={0,50,100}我没有意识到集合在python中没有排序;有趣的我实际使用的数据是以列表的形式提供的,因此我会记住已排序的注释。我应该如何处理开始/结束可能是缺失片段的边缘情况?对于缺失={8,9,56}或缺失={8,10,56}似乎不起作用。@RickHitchcock是的,在这种情况下,它应该生成9,9,它确实为{8,10,56}生成了9,9,@TheIncorrigible1它应该为{8,9,56}生成什么这是另一个边缘案例:missing={0,50,100}你能解释一下你的逻辑吗?看起来它勾选了所有的框,但我不熟悉groupby或屈服from@TheIncorrigible1我给我的答案加了一些解释。各方面都很好。如果缺少所有内容,甚至可以处理边缘情况。多谢各位much@TheIncorrigible1是的,这就是我喜欢itertools的原因:大多数情况下它都能很好地处理边缘情况,尽管有时不能——了解它们很好。你能解释一下你的逻辑吗?看起来它勾选了所有的框,但我不熟悉groupby或屈服from@TheIncorrigible1我给我的答案加了一些解释。各方面都很好。如果缺少所有内容,甚至可以处理边缘情况。多谢各位much@TheIncorrigible1是的,这就是我喜欢itertools的原因:它在大多数情况下都能很好地处理边缘情况,尽管有时不能——了解它们很好