Python循环遍历列表并返回"不按顺序排列"值

时间:2016-07-09 16:05:53

标签: python list loops

考虑这个清单:

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,我可以将它与原始列表进行比较,看看差距在哪里......很有意思。这是令人敬畏的蜂巢。

2 个答案:

答案 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 Reviewquestion 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)用作keyitemgetter(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)