【问题标题】:Python combine two lists of objects recursively by comparing datetimesPython 通过比较日期时间递归地组合两个对象列表
【发布时间】:2012-02-06 17:39:57
【问题描述】:

my previous question 开始,我现在正在读取两个文件 A 和 B,并将 2009 年的日期放入 AB2 对象列表 (subAB) 中的第一个非 2009 行中。

class AB2(object):
    def __init__(self, datetime, a=False, b=False):
        self.datetime = datetime
        self.a = a
        self.b = b
        self.subAB = []

例如:

file A: 20111225, 20111226, 20090101
file B: 20111225, 20111226, 20090101, 20090102, 20111227, 20090105

应导致:(方括号显示 subAB 列表)

AB2(20111225, a = true, b = true, [])
AB2(20111226, a = true, b = true, 
    [AB2(20090101, a = true, b = true, []),
     AB2(20090102, a = false, b = true, [])], 
AB2(20111227, a = false, b = true, 
    [AB2(20090105, a = false, b = true)]) 

不幸的是,这使之前的解决方案变得复杂:

list_of_objects = [(i, i in A, i in B) for i in set(A) | set(B)]

因为:

  • 顺序很重要(2009 年项目进入文件中第一个 2011 年项目)

  • 文件中可以有多个相同日期时间的项目

  • 现在也对 subAB 对象列表感兴趣

由于这些原因,我们不能使用当前存在的 set(因为它会删除重复项并丢失顺序)。我已经探索过使用OrderedSet recipe,但我想不出在这里应用它的方法。

我当前的代码:

listA = open_and_parse(file A) # list of parsed dates
listAObjects = [AB2(dt, True, None) for dt in listA] # list of AB2 Objects from list A
nested_listAObjects = nest(listAObjects) # puts 2009 objects into 2011 ones
<same for file B>
return combine(nested_listAObjects, nested_listBObjects)

嵌套方法:(将 2009 项放入前一个 2011 项中。如果 2009 项位于文件开头,则忽略它们)

def nest(list):
    previous = None
    for item in list:       
        if item.datetime.year <= 2009:
            if previous is not None:
                previous.subAB.append(item)
            else:
                previous = item

    return [item for item in list if item.datetime.year > 2009]

但我有点卡在combine 函数上:

def combine(nestedA, nestedB):
    combined = nestedA + nestedB
    combined.sort(key=lambda x: x.datetime)

    <magic>

    return combined

此时,如果没有魔法,combined 将如下所示:

AB2(20111225, a = true, b = None, []) # \ 
AB2(20111225, a = None, b = true, []) # / these two should merge to AB2(20111225, a = true, b = true, [])
AB2(20111226, a = true, b = None, 
    [AB2(20090101, a = true, b = None, []),
     AB2(20090102, a = true, b = None, [])], 
AB2(20111226, a = None, b = true, 
    [AB2(20090101, a = None, b = true, [])], 
# The above two lines should combine, and so should their subAB lists (but only recurse to that level, not infinitely)
AB2(20111227, a = None, b = true, 
    [AB2(20090105, a = None, b = true)]) 

我希望我可以发布一个新问题 - 这将是一个与我之前的问题完全不同的解决方案。也很抱歉这篇长文,我认为最好解释一下我正在做的所有事情,这样你才能完全理解问题,也许可以为整个问题提供替代解决方案,而不仅仅是combine 方法.谢谢!


编辑:澄清:

基本上,我正在检查来自两台已连接计算机的日志,并比较它们是在特定时间关闭,还是只关闭一台。如果计算机在检索到真正的 2012 时间之前重置,则计算机在 2009 时间启动(但并非总是在 1 月 1 日 - 有时是 1 月 4 日等)。因此,我试图将随后的 2009 年关闭与之前的关闭联系起来,以便我知道它何时会快速重置。

2011/2012 年的日期应该排序,但 2009 年的日期不是。一台计算机的日志文件(在我的示例中为fileA)可能如下所示:

2011/12/15
2011/12/17
2011/12/19 # Something goes wrong, and causes the computer to reset 5 times rapidly
2009/01/01 
2009/01/01
2009/01/04
2009/01/01
2011/12/20 # And everything is better again
2011/12/25

实际上,它们实际上是日期时间(例如2009/01/01 01:57:01),所以我可以简单地比较两个日期时间是否在某个timedelta 内。

我正在寻求一种更简洁的整体解决方案/方法,或者是针对将这两个 AB2 对象列表结合起来的问题的特定解决方案。

将两者结合起来最简单的方法是遍历已排序的组合列表(已将 2009 个对象放入其父项中),比较下一项是否与当前项的日期相同,并从中创建一个新列表项目。

【问题讨论】:

  • 我不清楚您要如何匹配 A 和 B 中的日期。文件未排序,但所有非 2009 日期是否按升序出现?非 2009 年的日期可以多次出现吗?
  • 我希望我可以发布一个新问题 - 当这是一个新问题时,发布一个新问题是正确的做法。
  • @JanneKarila 对不起,不清楚,我会编辑澄清。

标签: python list datetime recursion merge


【解决方案1】:

比较起来有点棘手,可能有一种更简洁的方法,但这似乎有效并且应该相对有效。

我假设日期的顺序很重要。增加的日期从两个输入流中比较并组合,当以前的日期出现时,它们被收集、组合并附加到前一个较大的日期。

为简洁起见,我刚刚在此示例中创建了元组而不是 AB2 类的实例。

from cStringIO import StringIO
fileA = StringIO("""20111225, 20111226, 20090101""")
fileB = StringIO("""20111225, 20111226, 20090101, 20090102, 20111227, 20090105""")

def fileReader(infile):
  for line in infile:
    for part in line.split(','):
      yield part.strip()

def next_or_none(iterable):
  for value in iterable:
    yield value
  yield None

def combine(a,b):
  current_val = None
  hasA = hasB = False
  next_a, next_b = next_or_none(a).next, next_or_none(b).next
  current_a, current_b = next_a(), next_b()
  while True:
    if current_val is None:
      if current_a == current_b:
        current_val = current_a
        hasA = hasB = True
        current_a, current_b = next_a(), next_b()
      elif current_a is not None and (current_b is None or current_a < current_b):
        current_val = current_a
        hasA = True
        current_a = next_a()
      elif current_b is not None and (current_a is None or current_b < current_a):
        current_val = current_b
        hasB = True
        current_b = next_b()
      else:
        break
    else: # There's a current_val
      sub_a = []
      while current_a is not None and current_a < current_val:
        sub_a.append(current_a)
        current_a = next_a()
      sub_b = []
      while current_b is not None and current_b < current_val:
        sub_b.append(current_b)
        current_b = next_b()
      if sub_a or sub_b:
        sub_ab = list(combine(sub_a,sub_b))
      else:
        sub_ab = []
      yield (current_val,hasA,hasB,sub_ab)
      current_val = None
      hasA = hasB = False

for row in combine(fileReader(fileA),fileReader(fileB)):
  print row

产量:

('20111225', True, True, [])
('20111226', True, True, [('20090101', True, True, []), ('20090102', False, True, [])])
('20111227', False, True, [('20090105', False, True, [])])

【讨论】:

  • 这看起来很有趣,谢谢!今晚我很难完全理解它,但明天早上我会试一试,看看我会怎么做:)
猜你喜欢
  • 2013-09-21
  • 2022-01-08
  • 2019-08-29
  • 2014-02-02
  • 1970-01-01
  • 2014-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多