考虑这个清单:
psycopg2 2.6.2
如何识别那些不按顺序的日期。我不在乎他们是否重复或跳过,我只是需要那些不合时宜的方式。即,我应该回来:
dates = [
('2015-02-03', 'name1'),
('2015-02-04', 'nameg'),
('2015-02-04', 'name5'),
('2015-02-05', 'nameh'),
('1929-03-12', 'name4'),
('2023-07-01', 'name7'),
('2015-02-07', 'name0'),
('2015-02-08', 'nameh'),
('2015-02-15', 'namex'),
('2015-02-09', 'namew'),
('1980-12-23', 'name2'),
('2015-02-12', 'namen'),
('2015-02-13', 'named'),
]
Namex不太明显,但它不在列表的一般顺序中。
我的简单开始(我已删除以简化问题)显然非常不完整。
更新:根据评论,似乎Longest Increase Subsequence(LIS)的实现会让我开始,这里有一个python实现:
似乎一旦我获得LIS,我可以将它与原始列表进行比较,看看差距在哪里......很有意思。这是令人敬畏的蜂巢。
答案 0 :(得分:1)
使用我的answer to the "Longest increasing subsequence" question,可以简单地实现:
def out_of_sequence(seq):
indices = set(longest_subsequence(seq, 'weak', key=lambda x: x[0], index=True))
return [e for i, e in enumerate(seq) if i not in indices]
基于question at Code Review和question about non-decreasing sequences(因为这就是您所追求的),这是您问题的解决方案:
from bisect import bisect_right
from operator import itemgetter
def out_of_sequence(seq, key = None):
if key is None: key = lambda x: x
lastoflength = [0] # end position of subsequence with given length
predecessor = [None] # penultimate element of l.i.s. ending at given position
for i in range(1, len(seq)):
# find length j of subsequence that seq[i] can extend
j = bisect_right([key(seq[k]) for k in lastoflength], key(seq[i]))
# update old subsequence or extend the longest
try: lastoflength[j] = i
except: lastoflength.append(i)
# record element preceding seq[i] in the subsequence for backtracking
predecessor.append(lastoflength[j-1] if j > 0 else None)
indices = set()
i = lastoflength[-1]
while i is not None:
indices.add(i)
i = predecessor[i]
return [e for i, e in enumerate(seq) if i not in indices]
print(*out_of_sequence(dates, itemgetter(0)), sep='\n')
输出:
('1929-03-12', 'name4')
('2023-07-01', 'name7')
('2015-02-15', 'namex')
('1980-12-23', 'name2')
key
参数(受sorted
内置启发)指定一个参数的函数,该函数用于从每个列表元素中提取比较键。默认值为None
,因此调用者可以方便地说“我想直接比较元素”。如果设置为None
,我们会将lambda x: x
用作identity function,因此在比较之前不会以任何方式更改元素。
在您的情况下,您希望将日期用作比较关键,因此我们将itemgetter(0)
用作key
。 itemgetter(1)
会将名称用作key
,请参阅:
>>> print(*map(itemgetter(1), dates))
name1 nameg name5 nameh name4 name7 name0 nameh namex namew name2 namen named
使用itemgetter(k)
相当于lambda x: x[k]
:
>>> print(*map(lambda x: x[1], dates))
name1 nameg name5 nameh name4 name7 name0 nameh namex namew name2 namen named
将其与map
一起使用等同于生成器表达式:
>>> print(*(x[1] for x in dates))
name1 nameg name5 nameh name4 name7 name0 nameh namex namew name2 namen named
但如果我们使用类似的列表推导将序列传递给out_of_sequence
,我们会得到与预期不同的结果:
>>> print(*out_of_sequence([x[0] for x in dates]), sep='\n')
1929-03-12
2023-07-01
2015-02-15
1980-12-23
同样,如果我们直接比较日期 - 名称对,我们会得到错误的结果(因为'nameg'
会比较大'name5'
):
>>> print(*out_of_sequence(dates), sep='\n')
('2015-02-04', 'nameg')
('1929-03-12', 'name4')
('2023-07-01', 'name7')
('2015-02-15', 'namex')
('1980-12-23', 'name2')
因为我们想要返回日期和名称,并且我们只想按日期排序,我们需要传递一个使用key
参数提取日期的函数。
另一种方法是摆脱key
并写下:
j = bisect_right([seq[k][0] for k in lastoflength], seq[i][0])
但由于这是stackoverflow,也许有一天,另一个人会得到这个答案,并需要一些其他的密钥提取,因此我决定在这里发布更通用的解决方案。
答案 1 :(得分:0)
如果当前日期大于上一个好日期,这将为您建立一个新的anchor_date。
import arrow
out_of_order = []
anchor_date = arrow.get(dates[0][0])
for dt, name in dates:
if arrow.get(dt) < anchor_date:
out_of_order.append((dt, name))
else:
anchor_date = arrow.get(dt)