满足一定条件时删除元素

时间:2016-03-18 09:49:58

标签: python list python-2.7

我有一个很大的清单:

@Html.PagedListPager(Model, page => Url.Action("Reporting",
    new { page, currentFilter = ViewBag.CurrentFilter, writerSearch = ViewBag.WriterSearch, publicationNoSearch = ViewBag.PublicationNoSearch, etc })

我想比较所有子列表对,例如

a=[[4,34,1], [5,87,2], [2,76,9],...]

然后应删除子列表a[i][0]>a[j][0] and a[i][1]>a[j][1] 。 我怎样才能在Python 2.7中实现这个目标?

4 个答案:

答案 0 :(得分:2)

这是实现@MisterMiyagi方法的一种惯用方式:

drop = set()
for i, j in itertools.combinations(range(len(a)), 2):
    # I would've used ``enumerate`` here as well, but it is
    # easier to see the filtering criteria with explicit 
    # indexing.
    if a[i][0] > a[j][0] and a[i][1] > a[j][1]:
        drop.add(i)

a = [value for idx, value in enumerate(a) if idx not in drop]
print(a)

它是如何更惯用的?

  • 来自itertools的组合迭代器,而不是双重forloop。
  • 切片中没有额外的0:
  • enumerate而不是显式索引来构建答案。

P.S。这是一个O(N ^ 2)解决方案,因此大型输入可能需要一段时间。

答案 1 :(得分:1)

如果您首先对列表进行排序(O(n log n)操作),则可以识别 通过比较邻居来保持(或拒绝)一次通过的项目(O(n) 操作)。因此,对于长列表,这应该比比较所有更快 对(O(n**2)操作)。

在帖子的底部,您会找到using_sort的代码:

In [22]: using_sort([[4,34,1], [5,87,2], [2,76,9]])
Out[22]: [[2, 76, 9], [4, 34, 1]]

In [23]: using_sort([[4, 34, 1], [5, 87, 2], [2, 76, 9], [4, 56, 12], [9, 34, 76]])
Out[23]: [[2, 76, 9], [4, 56, 12], [4, 34, 1], [9, 34, 76]]

我们可以根据Sergei Lebedev's answer将其与O(n**2)算法using_product进行比较。

首先,让我们检查它们是否给出相同的结果:

import numpy as np
tests = [
    [[4, 34, 1], [5, 87, 2], [2, 76, 9], [4, 56, 12], [9, 34, 76]],
    [[87, 26, 37], [50, 37, 23], [70, 97, 19], [86, 91, 55], [57, 55, 68],
     [25, 35, 64], [82, 79, 66], [1, 30, 75], [16, 14, 71], [32, 89, 6]],
    np.random.randint(100, size=(10, 3)).tolist(),
    np.random.randint(100, size=(50, 3)).tolist(),
    np.random.randint(100, size=(100, 3)).tolist()]

assert all([sorted(using_product(test)) == sorted(using_sort(test)) 
            for test in tests])

以下基准显示using_sortusing_product快得多。 由于using_sortO(n log n)using_productO(n**2), 速度优势随着a的长度而增加。

In [17]: a = np.random.randint(100, size=(10**4, 3)).tolist()

In [20]: %timeit using_sort(a)
100 loops, best of 3: 9.44 ms per loop

In [21]: %timeit using_product(a)
1 loops, best of 3: 6.17 s per loop

我发现可视化解决方案很有帮助。对于结果中的每个点都有 一个蓝色的矩形区域,从下面的给定点发出 左角。该矩形区域描绘了可以是的点集 由于这一点在结果中被淘汰。

使用using_sort时,每次在结果中找到一个点时,它会一直检查排序列表中的后续点,直到找到结果中的下一个点为止。

import itertools as IT
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
np.random.seed(2016)

def using_sort(a):
    if len(a) == 0: return []
    a = sorted(a, key=lambda x: (x[0], -x[1]))
    result = []
    pt = a[0]
    nextpt = pt
    for key, grp in IT.groupby(a, key=lambda x: x[0]):
        for item in grp:
            if not (item[0] > pt[0] and item[1] > pt[1]):
                result.append(item)
                nextpt = item
        pt = nextpt
    return result

def using_product(a):
    drop = set()
    for i, j in IT.product(range(len(a)), repeat=2):
        if (i != j 
            and i not in drop 
            and j not in drop
            and a[i][0] > a[j][0] 
            and a[i][1] > a[j][1]):
            drop.add(i)
    a = [value for idx, value in enumerate(a) if idx not in drop]
    return a

def show(a, *args, **kwargs):
    a = sorted(a, key=lambda x: (x[0], -x[1]))
    points = np.array(a)[:, :2]
    ax = kwargs.pop('ax', plt.gca())
    xmax, ymax = kwargs.pop('rects', [None, None])
    ax.plot(points[:, 0], points[:, 1], *args, **kwargs)
    if xmax:
        for x, y in points:
            rect = mpatches.Rectangle((x, y), xmax-x, ymax-y, color="blue", alpha=0.1)
            ax.add_patch(rect)

tests = [
    [[4, 34, 1], [5, 87, 2], [2, 76, 9], [4, 56, 12], [9, 34, 76]],
    [[87, 26, 37], [50, 37, 23], [70, 97, 19], [86, 91, 55], [57, 55, 68],
     [25, 35, 64], [82, 79, 66], [1, 30, 75], [16, 14, 71], [32, 89, 6]],
    np.random.randint(100, size=(10, 3)).tolist(),
    np.random.randint(100, size=(50, 3)).tolist(),
    np.random.randint(100, size=(100, 3)).tolist()]

assert all([sorted(using_product(test)) == sorted(using_sort(test)) 
            for test in tests])

for test in tests:
    print('test: {}'.format(test))
    show(test, 'o', label='test')
    for func, s in [('using_product', 20), ('using_sort', 10)]:
        result = locals()[func](test)
        print('{}: {}'.format(func, result))
        xmax, ymax = np.array(test)[:, :2].max(axis=0)
        show(result, 'o--', label=func, markersize=s, alpha=0.5, rects=[xmax, ymax])
    print('-'*80)
    plt.legend()
    plt.show()

enter image description here

答案 2 :(得分:0)

一种方法是通过迭代明确地做到这一点:

a = [[4,34,1], [5,87,2], [2,76,9]]
kill_list = set()
for i_idx, i_elems in enumerate(a):
  for j_idx, j_elems in enumerate(a):
    if i_idx in kill_list or j_idx in kill_list or j_idx <= i_idx:
      continue
    if i_elems[:2] > j_elems[:2]:
      kill_list.add(i_idx)
    if i_elems[:2] < j_elems[:2]:
      kill_list.add(j_idx)
a = [a[idx] for idx in range(len(a)) if idx not in kill_list]

答案 3 :(得分:0)

这有用吗?

a=[[4,94,1], [3,67,2], [2,76,9]]
b = a
c = []

for lista in a:
    condition = False
    for listb in b:
        if (lista[0] > listb[0] and lista[1] > listb[1]):
            condition = True
            break

    if not condition:
        c.append(lista)
然后,

c将包含您想要的列表列表。

编辑:根据谢尔盖的评论更改布尔条件。