使用最小迭代进行列表操作

时间:2013-07-10 19:11:01

标签: python list iteration

假设您有以下两个列表:

l1 = [0,30,45,55,80,90]
l2 = [35,65,70,75,100,120]

列表规则:

  1. `l1`始终从0开始,`l2`必须从大于0开始
  2. 列表必须按照从最小到最大的顺序排列
  3. 目标:

    基本上每个数字都是打开和关闭某个东西的索引。目标是返回l2中关闭l1

    中第一项的l2

    解释

    l1中的项目将“关闭”l1中距离最近的数字最近的项目。那么这两个数字都不再可用了。使用作为示例给出的列表,会发生这种情况:

    0打开

    30开启

    35关闭30

    45开启

    55打开

    65关闭55

    70关闭45

    75关闭0

    answer = 75

    我相信有一种方法可以做到这一点,只需遍历每个列表一次。我提出的方式,需要在事情结束时多次迭代def f(l1,l2): for x in l2: new_l = [i for i in l1 if i < x] closed = new_l[-1] if closed == 0: answer = x break else: l1.remove(closed) return answer 。所以在这个例子中,它必须迭代4次才能得到正确的答案。这是函数:

    {{1}}

    有没有办法检测什么关闭什么,所以我不需要根据需要迭代多次。在我的实际情况中,这可能需要数百次迭代,因为这个函数实际上将在一个可能会持续一段时间的循环中运行

4 个答案:

答案 0 :(得分:3)

您可以使用bisect模块:

import bisect
def f(l1,l2):
    for x in l2:
        ind = bisect.bisect(l1,x)
        # if the index where the item from l2 can fit in l1 is 1,
        # then it's time to return 
        if ind - 1 == 0:           
            return x
        del l1[ind-1]   #otherwise remove the item from l1


l1 = [0,30,45,55,80,90]
l2 = [35,65,70,75,100,120]
print f(l1,l2)
#75

答案 1 :(得分:1)

此问题是标准括号匹配问题的变体。主要的区别在于,开启器和闭门器不是单一的开启器和闭合器序列,而是编号,它们的顺序由它们的数字来定义。我们可以懒洋洋地将它们合并为一个序列,然后完成序列并保持未闭合开启者的计数,直到我们找到第一个开启者的更接近。这在O(n)中运行,其中n是第一个开启者的近点的索引。

def merge_iterator(openers, closers):
    """Goes through the openers and closers, merging the sequences.

    Yields (opener, 1) or (closer, -1) tuples, sorted by the values of the
    openers or closers. Each yield runs in O(1).

    """
    openers = iter(openers)
    closers = iter(closers)
    opener = next(openers)
    closer = next(closers)
    try:
        while True:
            if opener < closer:
                yield opener, 1
                opener = next(openers)
            else:
                yield closer, -1
                closer = next(closers)
    except StopIteration:
        # Ran out of openers. (We can't run out of closers first.)
        yield closer, -1
        for closer in closers:
            yield closer, -1

def find_closer(openers, closers):
    merged_sequence = merge_iterator(openers, closers)

    # open the first opener
    unclosed = 1
    next(merged_sequence)

    # open and close openers until the first opener closes
    for item, change_in_unclosed in merged_sequence:
        unclosed += change_in_unclosed
        if not unclosed:
            # We closed the first opener. Return the closer.
            return item

答案 2 :(得分:0)

这对你有用吗<​​/ p>

def findBiggest(L, val):
    """ Basically a modified binary search """
    if len(L) == 1:
        return L[0]
    elif L[len(L)/2] >= val:
        return biggest(L[:len(L)/2], val)
    else:
        return findBiggest(L[len(L)/2:], val)

def findOpens(opens, closes):
    for c in closes:
        opener = findBiggest(opens, c)
        opens.remove(opener)
        if opener == 0:
            print 'answer =', c
            return opener

答案 3 :(得分:0)

这应该是O(N)中的诀窍。

 def find_answer(l1, l2):
    opened = 0
    curr_l2 = 0

    for el in l1:
        if el > l2[curr_l2]:
            while curr_l2 < len(l2) and el > l2[curr_l2]:
                if opened == 1:
                    return l2[curr_l2]
                elif opened > 1:
                    # l2[curr_l2] closes an element.
                    opened -= 1
                    curr_l2 += 1
                else:
                    # Noone left to close
                    return None
        # `el` opens
        opened += 1
   # Remaining elements to close left
   return None