按其属性

时间:2015-05-28 08:51:48

标签: python sorting

我用一个简单的代码来组织我的todo.txt,其中包含Gina Trapani的语法,即上下文前面是@,项目前面是+,优先级标记为(A),(B )等。任务可以有多个上下文和项目。

我想要实现的是首先按上下文对行进行排序,并且在上下文块中,应该按项目排序,并且优先级的行首先出现在项目中。

我的代码到现在为止:

import os
import sys
import re

# Configuration
todo_path = notepad.getCurrentFilename()

def ordered_set(inlist):
    out_list = []
    for val in inlist:
        if not val in out_list:
            out_list.append(val)
    return out_list

class Todo:
    def __init__(self, priority, context, project, due, task, cdate):
        self.__priority = priority
        self.__context = context
        self.__project = project
        self.__due = due
        self.__task = task
        self.__cdate = cdate

    def __len__(self):
     return len(str(re.sub(' +',' ',str(self.__priority) +' '+' '.join(self.__context) + ' ' + ' '.join(self.__project) + ' ' + str(self.__due) + ' ' + str(self.__task) + ' ' + str(self.__cdate) + '\n')))

    def priority(self):
        return self.__priority

    def context(self):
        return self.__context

    def project(self):
        return self.__project

    def due(self):
        return self.__due

    def task(self):
        return self.__task

    def cdate(self):
        return self.__cdate

def BuildTodos():
 global todos
 todo_file = open(todo_path, 'r')
 raw_todos = todo_file.readlines()
 todo_file.close()
 todos = []

 for item in raw_todos:
  item = item.strip("\n")
  todos.append(item)
 console.write("Loaded Todos\n")
 for idx, item in enumerate(todos):  
  words = item.split(' ')  
  priority = [word for word in words if re.match('^\([A-Z]\)',word)]
  context = [word for word in words if word.startswith('@')]  
  project = [word for word in words if word.startswith('+')]  
  due = [word for word in words if word.startswith('due:')]  
  task = [word for word in words if not re.match('^\([A-Z]\)',word) and not word.startswith('@') and not word.startswith('+') and not word.startswith('due:') and not re.match('[0-9]{4}-[0-9]{2}-[0-9]{2}',word)]  
  cdate = [word for word in words if re.match('[0-9]{4}-[0-9]{2}-[0-9]{2}',word)]
  todos[idx] = Todo(priority, context, project, due, task, cdate)
 console.write("Built Todos\n")
 todos.sort(key=lambda t: t.context())
# ----------------
# HELP NEEDED HERE
# sort the lines by context and within the block of contexts lines  should be
# ordered by projects and lines with priorities comes first in the project.
# ---------------- 

def OutTodos():
 for t in todos:
    console.write(re.sub(' +',' ',' '.join(t.priority()) + ' ' + ' '.join(t.context()) + ' ' + ' '.join(t.project()) + ' ' + ' '.join(t.due()) + ' ' + ' '.join(t.task()) + ' ' + ' '.join(t.cdate()) + '\n'))

console.clear()
BuildTodos()
OutTodos()

示例todo.txt文件,包含utf-8个字符(!):

(A) @personal +study +python organize todo.txt áőúíéá
(A) Schedule annual checkup +Health áőúíéá
(B) Outline chapter 5 +Novel @Computer áőúíéá
(C) Add cover sheets @Office +TPSReports áőúíéá
Plan backyard herb garden @Home áőúíéá
Pick up milk @GroceryStore áőúíéá
Research self-publishing services +Novel @Computer áőúíéá
Download Todo.txt mobile app @Phone áőúíéá

我在如何构建这种排序方面挤压我的想法,以便不以怪物结束。我的猜测是迭代todos列表,并且有级联ifs,但没有任何python中的排序/列表操作经验我会提出建议。

1 个答案:

答案 0 :(得分:2)

我认为使用有序词典是前进的方法,这样你就可以将每行中的所有数据保存在一起,然后就可以搞清楚你想要它的打印方式。

dicts唯一的问题是他们总是需要一个密钥,因为你不总是提供一个上下文/项目/优先级。为了解决这个问题,我添加了' zzz'当没有可用时(这有助于排序,稍后将删除)。

我也遇到了你正在使用的.difference的问题,因为我认为它依赖于一个集合,即没有重复的数据,比如"这样做我想要"其中一个' to将被删除。

无论如何这里是代码(Python 2.7):

import re
import collections
import sys

fname = "todo.txt"
jobs = {}
myset = set()

#Recursive printing. Also orders the dictionary and removes zzz
def rprint(d):
   a = collections.OrderedDict(sorted(d.items()))
   for key, value in a.iteritems():
      if isinstance(value, dict):
         rprint(value)
      else:
         # check to see if the line is a repitition, this can occour
         # when a line has more than one priority/project/context.
         for line in value:
             if line not in myset:
                 print str(line)
                 myset.add(line)


with open(fname) as f:
    for line in f:

      line = line.strip()
      words = line.split(' ')
      priority = [word for word in words if re.match('^\([A-Z]\)',word)]
      context = [word for word in words if word.startswith('@')]
      project = [word for word in words if word.startswith('+')]

      #Need to make sure that there is always a key otherwise it will cause 
      #the dict issues, set key to zzz so that it will appear at the bottom when sorted
      if not priority: priority = ["zzz"]
      if not project:  project = ["zzz"]
      if not context:  context = ["zzz"]

      for i in context:
          for j in project:
              for k in priority:

                  if i not in jobs:
                      jobs[i] = {}
                  if j not in jobs[i]:
                      jobs[i][j] = {}
                  if k not in jobs[i][j]:
                      jobs[i][j][k] = []

                  jobs[i][j][k].append(line)

    rprint(jobs)