Reputation: 129
First off, my apologies for the title, I'm not sure how to solve this issue to be more specific.I'm trying to create a script to collect a list of Next Actions (as in the Getting Things Done method) based on an entire list of Projects using the TaskPaper formatting. This is an example of the sort of string that will go into the script.
Inbox:
Project 01:
- Task 01
- Task 02
- Task 03
Project 02:
- Task 01
- Task 02
- Task 03
- Task 04
I managed to make a list out of every project within a main list I can loop into. This is the actual state of my script. Please consider arg[1]
as the aforementioned string:
allTasks = arg[1].split('\n\n')
projects = [filter(None,proj.split('\n')) for proj in allTasks]
next_actions = [task[:2] for task in projects if len(task) > 1]
The variable next_actions
will result in the following list: [['Project 01:', '\t- Task 01'], ['Project 02:', '\t- Task 01']]
which is exactly as I want it, however, if I add subtasks to one of those tasks, like this:
Project 01:
- Task 01
- Subtask 01
- Subtask 02
- Subtask 03
- Task 02
- Task 03
And run the script, my next_actions
variable doesn't change (and I know why, but I don't know how to solve it). I wanted the outcome to be: [['Project 01:', '\t- Task 01\n\t\t- Subtask 01\n\t\t- Subtask 02\n\t\t- Subtask 03'], ['Project 02:', '\t- Task 01']]
so I could support subtasks. Perhaps identifying a task with subtasks earlier on and making a list out of them could solve my issue, but I don't know where to start.
Did I miss any information you'd need? Please let me know and I'll reply as soon as possible. Thank you for the help.
Upvotes: 1
Views: 355
Reputation: 129
I found a reasonable solution using re.split()
re.split('\n(?=^\t-\s)', arg[1], 0, re.M)
Being arg[1] the full string of tasks, this action will split on the line break \n
previous to every task, which has solely a single task. Considering the following string:
Project 01:
- Task 01
- Subtask 01
- Subtask 02
- Subtask 03
- Task 02
- Task 03
The aforementioned re.split() will create this list:
['Project 01:', '\t- Task 01\n\t\t- Subtask 01\n\t\t- Subtask 02\n\t\t- Subtask 03', '\t- Task 02', '\t- Task 03']
Afterwards, I can just approach each "Project" individually using project[:2]
in a loop to collect the next action per project according to the real intentions of this question. Thank you, Pedro for helping me out the whole time (:
Upvotes: 1
Reputation: 31
Disregard the previous answer. I, as usual overcomplicated things. This should prove to be simpler and shorter while still rendering the desired results.
Source List
t = '''Inbox:
Project 01:
- Task 01
this is a comment
this is still a comment associate with task 01
- sub 01
- sub 02
- sub 05
- Task 02
- Task 03
- sub 03
- sub 04
Project 02:
- Task 01
- proj 2 sub 01
- Task 02
- Task 03
- Task 04'''
Script
allTasks = t.split('\n\n')
projects = [filter(None,proj.split('\n\t')) for proj in allTasks]
for i in projects:
if len(i[1:])>0:
print i[0]
print i[1]
for s in range(2,len(i[1:])):
if i[s].startswith("\t") or not i[s].startswith("-"):
print i[s]
else:
break
Output
Project 01:
- Task 01
this is a comment
this is still a comment associate with task 01
- sub 01
- sub 02
- sub 05
Project 02:
- Task 01
- proj 2 sub 01
While using less code, this also keeps the order of your projects.
Upvotes: 1
Reputation: 31
While far from elegant or possibly the best approach, I believe that you should leverage nested data structures for this task.
Given the following dictionary of Tasks:
t = {'Inbox':[],
'Project 01': [
['Task 01',['subtask 1', 'subtask 2']],
'Task 02',
'Task 03'
],
'Project 02':[
['Task 01',['subtask 1', 'subtask 2','subtask 3', 'subtask 4']],
'Task 02',
'Task 03',
'Task 04'
]
}
This code should handle next actions that have subtasks with relative ease.
print "Next Actions"
for i in t:
if len(t[i]) > 0:
print "\n%s:" %i
if isinstance(t[i][0], list):
print "- %s" %(t[i][0][0])
for st in t[i][0][1]:
print "\t- %s" %(st)
else:
print t[i][0]
This will output:
Next Actions
Project 01:
- Task 01
- subtask 1
- subtask 2
Project 02:
- Task 01
- subtask 1
- subtask 2
- subtask 3
- subtask 4
Alternatively and using your initial list and code as a starting point, you could achieve the desired result in the following manner. Note that this will also handle comments associated to the next action.
Given the list
t = '''Inbox:
Project 01:
- Task 01
this is a comment
this is still a comment associate with task 01
- sub 01
- sub 02
- sub 05
- Task 02
- Task 03
- sub 03
- sub 04
Project 02:
- Task 01
- proj 2 sub 01
- Task 02
- Task 03
- Task 04'''
The following code should give you the results you're after. Now I've only tested this with limited data and I'm sure there should be a more optimal way, but for now this is what I've got:
temp_list = {}
temp_sub = []
final_list = {}
allTasks = t.split('\n\n')
projects = [filter(None,proj.split('\n\t')) for proj in allTasks]
for i in projects:
temp_list[i[0]]=i[1:]
for key,value in temp_list.iteritems():
if len(value) > 0:
temp_sub = []
for s in range(1,(len(value)-1)):
if value[s].startswith('\t') or not value[s].startswith('-'):
temp_sub.append(value[s])
else:
break
final_list[key]=[value[0],temp_sub]
for key, value in final_list.iteritems():
print key
for sub in value:
if len(value)>0 and len(sub)>0:
if isinstance(sub, list):
for item in sub:
print item
else:
print sub
And once again, the output will be:
Project 02:
- Task 01
- proj 2 sub 01
Project 01:
- Task 01
this is a comment
this is still a comment associate with task 01
- sub 01
- sub 02
- sub 05
Now since we're creating the dictionary on the fly, your end results (projects) will loose order. Additional code would be necessary to maintain some form of ordering I think.
Upvotes: 2