获取连接范围列表的索引

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了获取连接范围列表的索引相关的知识,希望对你有一定的参考价值。

我有一个范围列表,该列表中的所有范围都有同样的 startstop但不一样 step......例如:......................................................................................................................................................................................................................................:

[range(0, 10, 2), range(0, 10, 3)]

当然,这个列表可以包含超过2个范围。并列的范围列表表示以下数字。

[0, 2, 3, 4, 6, 8, 9]

我想得到 x 并列的范围列表的索引。例如,最后一个例子的5索引将是 8.

问题是,这个范围可能很大(几百万),我不想把这个范围变成一个列表来获取 x 索引。我需要以某种方式来计算该指数的值。x 索引,而不需要 "打开 "该范围列表

试着想了几个小时,想出一个算法来做,我找到的最好的解决方案包括使用二进制搜索来做,我认为这不是理想的方式。

有什么办法可以让我达到这个目的吗?

答案

你可以制作一个新的 range 一样 startend,并打包所有 step到一个新的列表中。现在你可以检查范围内的每一个数字是否符合 任何 步。你可以把它做成一个生成器。

def steps_range(start, end, steps):
    for i in range(start, end):
        if any(i % x == 0 for x in steps):
            yield i

现在你可以在这个生成器上循环,直到你到达相关的索引。根据你的例子。

ranges = [range(0, 10, 2), range(0, 10, 3)]

start = ranges[0].start
end = ranges[0].stop
steps = [r.step for r in ranges]

target_index = 5

for i, num in enumerate(steps_range(start, end, steps)):
    print(num)
    if i == target_index:
        break

这个就会被打印出来

0
2
3
4
6
8
另一答案

关键点是要使用 yield.

困难的是如何处理这种情况,当一个人有一个人的时候。yield 端。最后我选择的解决方案是用dict,用 min 得到 iterator 谁要搬家next). 并检查是否有 iterator 到最后。如果是,就把它从 dict.

#!/usr/bin/env python3
import operator


class IterTool:
    def __init__(self, the_range):
        def foo(the_range):
            def bar():
                for i in the_range:
                    yield i
            return bar()

        self.the_range = foo(the_range)
        self.end = False

    def next_item(self):
        try:
            foo = next(self.the_range)
            return foo
        except StopIteration:
            self.end = True

    def is_end(self):
        return self.end


pool = {}
for i in [IterTool(range(0, 10000000000000, 2)), IterTool(range(0, 10000000000000, 3))]:
    pool[i] = i.next_item()
idx = 0
last_val = None
while all(map(lambda x: not x.is_end(), pool)):
    if len(pool) == 0:
        break
    key = min(pool.items(), key=operator.itemgetter(1))[0]
    val = pool[key]
    if val != last_val:
        if idx == 99999:
            print("%s=> %s" % (idx, val))
            break
        idx += 1
        last_val = val
    pool[key] = key.next_item()
    if key.is_end():
        del pool[key]

结果。

99999=> 149998

real    0m0.209s
user    0m0.200s
sys     0m0.004s
另一答案
def is_not_divisible_by_any(num, divs):
    return all(num % divisor for divisor in divs)

def get_idx_of_concated_list(the_list, idx):
    # Get the start, end and steps
    start, end = the_list[0].start, the_list[0].stop
    shifted_end = end - start
    steps = [r.step for r in the_list]

    # Get the number of numbers non-divisble by the steps until the given index (inclusive)
    num_not_divisibles = sum(is_not_divisible_by_any(num, steps) for num in range(idx+1))

    # The first candidate will be the given index + the above number of non-divisibles
    candidate = idx + num_not_divisibles

    # Forward by one till it is divisible by any of the steps
    while is_not_divisible_by_any(candidate, steps):
        candidate += 1

    # Check if the given index was valid
    if candidate > shifted_end:
        raise ValueError("The given index with those ranges exceed the stop value")

    # Since assumed start = 0, add the original start
    return candidate + start

# Example:
concat_list = [range(0, 1_000_000, 2), range(0, 1_000_000, 3), range(0, 1_000_000, 7)]
idx = 225_000
print(get_idx_of_concated_list(concat_list, idx))
# 289286

解释:在不失一般性的前提下,我们假设起点是0(我们可以很容易地在最后把原来的起点加回来,你会看到)。那么,我们基本上有以下序列。

0, 1, 2, 3, 4, 5, ..., stop-1

如果,对于这个序列,我们被要求在以下位置找到值: x'th指数,我们会直接说 x 作为答案。然而,在这个序列中,范围的步骤会跳过一些值。例如,如果步骤是2和3,我们就会得到 0, 2, 3, 4, 6, .. 以此类推。因此,如果我们能找到那些跳过的数字中不被任何给定步骤(直到给定指数,包括在内)所整除的数字,那么我们只需将其相加,就能得到解题的候选数,但候选数仍可能不被任何步骤整除。

例如,考虑到你在问题中的例子,不被除数的数目是2(1和5),我们将2加到给定的指数5上,得到7;但这并不能均匀地除以2或3)。因此,我们做一个增量搜索,由 candidate 等,直到我们找到我们想要的值。最后,因为我们假设start为0,所以我们把原来的start值加回来,得到结果。

编辑:我为索引添加了一个检查,使其不超过停止值。

以上是关于获取连接范围列表的索引的主要内容,如果未能解决你的问题,请参考以下文章

获取不使用索引的连接的 MySQL 查询列表

列表索引超出范围错误:Python

QQmlApplicationEngine 列表索引超出范围问题

活动结果片段索引超出范围:0x20001

Python构建二维数组获取列表分配索引超出范围

Python列表和范围