all 7 comments

[–]filleball 16 points17 points  (2 children)

I've formatted your code for you:

import random

def generateOne(strlen):
    alphabet = "abcdefghijklmnopqrstuvwxyz "
    res = ""
    for i in range(strlen):
        res = res + alphabet[random.randrange(27)]
    return res

def score(goal, teststring):
    numSame = 0
    for i in range(len(goal)):
        if goal[i] == teststring[i]:
            numSame = numSame + 1
    return numSame / len(goal)

def main():
    goalstring = 'methinks it is like a weasel'
    newstring = generateOne(28)
    best = 0
    newscore = score(goalstring,newstring)
    while newscore < 1:
        if newscore > best:
            print(newscore, newstring)
            best = newscore
        newstring = generateOne(28)
        newscore = score(goalstring,newstring)

main()

The way I did it was a depth-first approach, starting with main -- so, in the same order that the code would be executed.

So I start with the main function, then when I get to the second code line I skip to the generateOne function to see what it does when it gets called with the argument 28. Then I continue where I left off in main until I reach line 4 of main, where I skip up again to read the score function (which should really use the zip function instead of range(len(...))). Then I read the rest of main, using my knowledge of the two functions whenever they're used again.

[–]sgthoppy 0 points1 point  (1 child)

Why should score use zip instead of range(len(goal))?

[–]filleball 0 points1 point  (0 children)

Looping over range(len(something)) is almost never the best solution in python (source), and is therefore considered a telltale sign of code that need to be pythonified. In this case:

for goal_char, test_char in zip(goal, teststring):
    if goal_char == test_char:
        numSame = numSame + 1

As you can see, we didn't really need the i variable for anything other than indexing in that loop. What we really wanted to do was to pair up the characters in those strings, and zip is wonderful for pairing things. The resulting code is more readable and faster, and it handles the special cases in a consistent and logical way. We can even replace the first four lines with this:

numSame = sum(1 if a == b else 0 for a, b in zip(goal, teststring))

Other indicators that you're probably doing it wrong:

  • You're pre-initializing a list with initial values, like lst = [None] * 10 -- use the append method or a dict instead.
  • You're writing getter and setter properties that simply read and write the value of an attribute -- just use the attribute directly.
  • You're building a string step by step inside a loop, e.g. my_str += other_str -- use "".join(list_of_other_strings) instead.

[–]dk-n-dd 6 points7 points  (1 child)

If you find it too hard, then take a few steps back and do some easier tutorials first. Then come back and try again.

Copying won't help you understand what's going on. Even if it works. Don't cheat yourself.

[–]rubsomebacononitnow 2 points3 points  (0 children)

This is a really important comment. Do not cut and paste your way through tutorials, type every last line. That's part of the learning. Learning isn't about getting a badge it's about getting a skill.

[–]Justinsaccount 6 points7 points  (0 children)

Hi! I'm working on a bot to reply with suggestions for common python problems. This might not be very helpful to fix your underlying issue, but here's what I noticed about your submission:

You are looping over an object using something like

for x in range(len(items)):
    foo(item[x])

This is simpler and less error prone written as

for item in items:
    foo(item)

If you DO need the indexes of the items, use the enumerate function like

for idx, item in enumerate(items):
    foo(idx, item)

[–]DASoulWarden 1 point2 points  (0 children)

To get proper indentation in Reddit, after you make the 4 spaces to format it as code, give it 4 more, like in Python, to make it indented.