【问题标题】:Sort a subset of a python list to have the same relative order as in other list对 python 列表的子集进行排序,使其具有与其他列表相同的相对顺序
【发布时间】:2015-05-28 10:44:00
【问题描述】:

所以有一个列表说b = [b1, b2, b3] 我希望能够对列表a 进行排序,这样a 中也存在的所有bi 具有与@987654325 中相同的相对顺序@ - 不理会a 的其余元素。所以

a = [ b1, x, b3, y, b2] -> [ b1, x, b2, y, b3]
a = [ b1, x, b2, y, b3] -> no change
a = [ b1, x, y, b2]     -> no change
a = [ b3, x, b1, y, b2] -> [ b1, x, b2, y, b3]

b 当然可以是元组或任何其他有序结构。我想出了什么

bslots = dict((x, a.index(x)) for x in a if x in b)
bslotsSorted = sorted(bslots.keys(), key=lambda y: b.index(y))
indexes = sorted(bslots.values())
for x,y in zip(bslotsSorted, indexes):
  a[y] = x

笨拙且 O(n^2)

【问题讨论】:

    标签: python algorithm list python-2.7 sorting


    【解决方案1】:
    • 首先使用来自b的项目创建一个字典,其中键是项目,值是它的索引,稍后我们将使用它对a中的匹配项目进行排序。

      李>
    • 现在从 a 中过滤掉该 dict 中存在的项目,dict 提供 O(1) 查找。

    • 现在对该过滤项列表进行排序并将其转换为迭代器。

    • 现在再次循环 a 并检查每个项目是否存在于 dict 中,然后从迭代器中获取其值,否则按原样使用它。

    def solve(a, b):
        dct = {x: i for i, x in enumerate(b)}
        items_in_a = [x for x in a if x in dct]
        items_in_a.sort(key=dct.get)
        it = iter(items_in_a)
        return [next(it) if x in dct else x for x in a]
    ...
    >>> b = ['b1', 'b2', 'b3']
    >>> a = [ 'b1', 'x', 'b3', 'y', 'b2']
    >>> solve(a, b)
    ['b1', 'x', 'b2', 'y', 'b3']
    >>> a = [ 'b1', 'x', 'b2', 'y', 'b3']
    >>> solve(a, b)
    ['b1', 'x', 'b2', 'y', 'b3']
    >>> a = [ 'b1', 'x', 'y', 'b2']
    >>> solve(a, b)
    ['b1', 'x', 'y', 'b2']
    >>> a = [ 'b3', 'x', 'b1', 'y', 'b2']
    >>> solve(a, b)
    ['b1', 'x', 'b2', 'y', 'b3']
    

    总体时间复杂度将达到(O(len(a)), O(len(b)), O(items_in_a_length log items_in_a_length) 的最大值。

    【讨论】:

    • 请注意,这要求b 中的对象是可散列的。如果b 中的对象是集合或列表(等),您可以使用原始id 作为查找值。
    【解决方案2】:

    接受的答案按要求回答了问题,但我的实际问题更具限制性 - 即我希望尽可能将项目保持在 a 中的相同相对位置。因此,接受的答案(以及我最初的尝试)将:

    b = [ A, E, B ]
    a = [ A, B, C, D, E, Z] -> [ A, E, C, D, B, Z ]
    

    我只想“冒泡”乱序商品,以便它们尽可能少地失去祖先:[ A, B, C, D, E, Z ] -> [ A, C, D, E, B, Z ]。请注意,以前 E 会失去祖先 C 和 D,而现在只根据需要失去 B。勉强测试:

    def reorder(a, b):
        bb = b[:]
        b_in_a = [x for x in a if x in set(b)]
        w = dict((x, i) for i, x in enumerate(a))
        while b_in_a:
            for i, (ordered, current) in enumerate(zip(bb, b_in_a)):
                if ordered != current:
                    for j, x in enumerate(b_in_a[i:]):
                        if x == ordered: break
                        to = w[ordered] + 1 + j
                        w = dict((x,i if i < to else i+1) for x,i in w.iteritems())
                        w[x] = to # bubble them up !
                    b_in_a.remove(ordered)
                    bb = bb[i + 1:]
                    b_in_a = b_in_a[i:]
                    break
            else:
                break
        aa = a[:]
        a.sort(key=w.__getitem__)
        print aa, '-', b, ' -> ', a
    
    # ['A', 'B', 'C', 'D', 'E'] - ['A', 'E', 'B']  ->  ['A', 'C', 'D', 'E', 'B']
    # ['A', 'B', 'C', 'D', 'E', 'F'] - ['A', 'E', 'C', 'B']  ->  ['A', 'D', 'E', 'C', 'B', 'F']
    

    【讨论】:

    • @AshwiniChaudhary:对这个有什么巧妙的优化吗?
    猜你喜欢
    • 2011-02-03
    • 1970-01-01
    • 2019-09-24
    • 2022-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-07
    • 2012-12-07
    相关资源
    最近更新 更多