我有一个很大的清单:
@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中实现这个目标?
答案 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_sort
比using_product
快得多。
由于using_sort
为O(n log n)
而using_product
为O(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()
答案 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将包含您想要的列表列表。
编辑:根据谢尔盖的评论更改布尔条件。