user1839493
user1839493

Reputation: 63

How to find the smallest N

I have a code that determines the survivor from a list of names to walk the plank in this scenario, the last person in the list survives the code i have for this is:

names =  ["Andrew", "Brenda", "Craig", "Deidre", "Edward", "Felicity", "Greg", "Harriet"]
def survivor(names, step):
    Next = step - 1
    while len(names) > 1:
        names.pop(Next)
        Next = Next + step
        Next = (Next - 1) % len(names)
        print names

    return names[0]

this works to return the survivor based on what put in step but i also need to work out the smallest N for step for a person to survive e.g. 3 for greg and 2 for andrew.

the codes i have tried for this are:

assert name in names
for step in survivor(names, step):
    if survivor == name:
        return step

but it keeps saying local variable step referenced before assignment or global step is not defined.

and

assert name in names
for step in itertools.count(1):
    if survivor(names, step) == name:
        return step

but this returns

['Brenda', 'Craig', 'Deidre', 'Edward', 'Felicity', 'Greg', 'Harriet']

['Craig', 'Deidre', 'Edward', 'Felicity', 'Greg', 'Harriet']

['Deidre', 'Edward', 'Felicity', 'Greg', 'Harriet']

['Edward', 'Felicity', 'Greg', 'Harriet']

['Felicity', 'Greg', 'Harriet']

['Greg', 'Harriet']

['Harriet']

which is not what i want

Can anyone help me work this out?

Upvotes: 0

Views: 168

Answers (2)

Brendan Long
Brendan Long

Reputation: 54242

for step in survivor(names, step):

Notice how you're using step twice here. How is Python supposed to pass it to the survivor function before it gets it out of that function?

I think what you want is the range function. This will loop through every step value from 1 to the length of the list of names:

for step in range(1, len(names)):

Your itertools.count version should also work, now that I think about it. Are you checking the return value of this function or just looking at what it prints out? The output looks like it's from this line:

print names

One other thing is that your function changes the original list every time it runs, since you change names and you're not making a copy. Maybe you want to make a copy before changing it:

def survivor(names, step):
    names = names[:]
    # etc

See this question for why names[:] creates a copy of the list.

Upvotes: 1

jadkik94
jadkik94

Reputation: 7068

This loop does not do what you expect. What you want should be similar to this:

def shortest(name):
    assert name in names
    for step in range(1, len(names)+1):
        #Go through all possible steps, from 1 to number of items (the +1 is to include the last item too)
        if survivor(names[:], step) == name: # Check that this item matches
            return step # Break out of the loop when you get to it

The itertools.count(1) would work, but you could just as well use a while True and it makes no sense to have a step greater than the length of the names list.

Your problem was probably with the names array becoming empty after the first name. Because you are poping out all the elements, and modifying the names list which is in the global scope (defined out of the function). So you have to duplicate it (using either names[:] or list(names) which will both achieve the same purpose).

That's the test I made:

for n in names:
    print n, shortest(n)

And the output:

Andrew 2
Brenda None
Craig 5
Deidre 7
Edward None
Felicity 4
Greg 3
Harriet 1

Note: I don't know why there are Nones in there... but the examples you gave did match!

Upvotes: 2

Related Questions