tags:

views:

182

answers:

5

I'm trying to create a list of tasks that I've read from some text files and put them into lists. I want to create a master list of what I'm going to do through the day however I've got a few rules for this.

One list has separate daily tasks that don't depend on the order they are completed. I call this list 'daily'. I've got another list of tasks for my projects, but these do depend on the order completed. This list is called 'projects'. I have a third list of things that must be done at the end of the day. I call it 'endofday'.

So here are the basic rules.

A list of randomized tasks where daily tasks can be performed in any order, where project tasks may be randomly inserted into the main list at any position but must stay in their original order relative to each other, and end of day tasks appended to the main list.

I understand how to get a random number from random.randint(), appending to lists, reading files and all that......but the logic is giving me a case of 'hurty brain'. Anyone want to take a crack at this?

EDIT:

Ok I solved it on my own, but at least asking the question got me to picture it in my head. Here's what I did.

random.shuffle(daily)
while projects:
    daily.insert(random.randint(0,len(daily)), projects.pop(0))
random.shuffle(endofday)
daily.extend(endofday)
for x in daily: print x

Thanks for the answers, I'll give ya guys some kudos anyways!

EDIT AGAIN:

Crap I just realized that's not the right answer lol

LAST EDIT I SWEAR:

position = []
random.shuffle(daily)
for x in range(len(projects)):
    position.append(random.randint(0,len(daily)+x))
position.sort()
while projects:
    daily.insert(position.pop(0), projects.pop(0))
random.shuffle(endofday)
daily.extend(endofday)
for x in daily: print x

I LIED:

I just thought about what happens when position has duplicate values and lo and behold my first test returned 1,3,2,4 for my projects. I'm going to suck it up and use the answerer's solution lol

OR NOT:

position = []
random.shuffle(daily)
for x in range(len(projects)):
    while 1:
        pos = random.randint(0,len(daily)+x)
        if pos not in position: break
    position.append(pos)
position.sort()
while projects:
    daily.insert(position.pop(0), projects.pop(0))
random.shuffle(endofday)
daily.extend(endofday)
for x in daily: print x
+1  A: 

Use random.shuffle to shuffle a list

random.shuffle(["x", "y", "z"])

+1  A: 

How to fetch a random element in a list using python:

>>> import random
>>> li = ["a", "b", "c"]
>>> len = (len(li))-1
>>> ran = random.randint(0, len)
>>> ran = li[ran]
>>> ran
'b'

But it seems you're more curious about how to design this. If so, the python tag should probably not be there. If not, the question is probably to broad to get you any good answers code-wise.

mizipzor
Uh? Python's random module and its specific approaches to lists and generators are quite germane to how best to design this (see my answer) and the Python code essentially expresses the design...
Alex Martelli
While you are correct that this task is quite well suited for the Python language, I was a bit confused if he wanted help with coding a design, or if he needed help with the design in the first place. Both are valid questions, but asking both at the same time can be a bit much.
mizipzor
+3  A: 

First, copy and shuffle daily to initialize master:

master = list(daily)
random.shuffle(master)

then (the interesting part!-) the alteration of master (to insert projects randomly but without order changes), and finally random.shuffle(endofday); master.extend(endofday).

As I said the alteration part is the interesting one -- what about:

def random_mix(seq_a, seq_b):
    iters = [iter(seq_a), iter(seq_b)]
    while True:
        it = random.choice(iters)
        try: yield it.next()
        except StopIteration:
            iters.remove(it)
            it = iters[0]
            for x in it: yield x

Now, the mixing step becomes just master = list(random_mix(master, projects))

Performance is not ideal (lots of random numbers generated here, we could do with fewer, for example), but fine if we're talking about a few dozens or hundreds of items for example.

This insertion randomness is not ideal -- for that, the choice between the two sequences should not be equiprobable, but rather with probability proportional to their lengths. If that's important to you, let me know with a comment and I'll edit to fix the issue, but I wanted first to offer a simpler and more understandable version!-)

Edit: thanks for the accept, let me complete the answer anyway with a different way of "random mixing preserving order" which does use the right probabilities -- it's only slightly more complicated because it cannot just call random.choice;-).

def random_mix_rp(seq_a, seq_b):
    iters = [iter(seq_a), iter(seq_b)]
    lens = [len(seq_a), len(seq_b)]
    while True:
        r = random.randrange(sum(lens))
        itindex = r < lens[0]
        it = iters[itindex]
        lens[itindex] -= 1

        try: yield it.next()
        except StopIteration:
            iters.remove(it)
            it = iters[0]
            for x in it: yield x

Of course other optimization opportunities arise here -- since we're tracking the lengths anyway, we could rely on a length having gone down to zero rather than on try/except to detect that one sequence is finished and we should just exhaust the other one, etc etc. But, I wanted to show the version closest to my original one. Here's one exploiting this idea to optimize and simplify:

def random_mix_rp1(seq_a, seq_b):
    iters = [iter(seq_a), iter(seq_b)]
    lens = [len(seq_a), len(seq_b)]
    while all(lens):
        r = random.randrange(sum(lens))
        itindex = r < lens[0]
        it = iters[itindex]
        lens[itindex] -= 1
        yield it.next()
    for it in iters:
        for x in it: yield x
Alex Martelli
+1  A: 
  1. Combine all 3 lists into a DAG
  2. Perform all possible topological sorts, store each sort in a list.
  3. Choose one from the list at random
+1  A: 

In order for the elements of the "project" list to stay in order, you could do the following: Say you have 4 project tasks: "a,b,c,d". Then you know there are five spots where other, randomly chosen elements can be inserted (before and after each element, including the beginning and the end), while the ordering naturally stays the same.

Next, you can add five times a special element (e.g. "-:-") to the daily list. When you now shuffle the daily list, these special items, corresponding to "a,b,c,d" from above, are randomly placed. Now you simply have to insert the elements of the "projects" list sequentially for each special element "-:-". And you keep the ordering, yet have a completely random list regarding the tasks from the daily list.

err, I mean 4 times the special element. Otherwise it would not match up...