Question

my first time asking something here. I have a text file of names, 1 name per line, that i'm reading in to a list, and then duplicating that list twice, the first time to remove \n's and a second time to lowercase the list. then I ask the user for a search term, and convert their input to lowercase, and then search the lowercase version of the list for that, then i get the index of the match, and use that to display the non-lowercase version of that list item back to the user (so they can type for example anivia and get back Anivia). This is working fine but I'm sure my code is pretty bad. What I would like to do is add specific abreviations for some of the names in the list file, and accept those abbreviations as input, but still display back the full name. For example, user enters "mumu" and it sees that the list has Amumu - mumu, to reference Amumu. How could I go about accepting that abreviation? Also other cases like mf for Miss Fortune or kha for Kha'Zix. I thought of maybe having a second file contain the list of abbreviations but that seems so wasteful and I'm sure theres a better way. Here is my bad code so far:

f = open("champions.txt") #open the file
list = f.readlines() #load each line into the list
#print list
list2 = [item.rstrip('\n') for item in list] #remove trailing newlines in copy list
list3 = [item.lower() for item in list2] #make it all lowercase

print "-------\n", list2 #print the list with no newlines just to check

print "which champ" #ask user for input
value = raw_input().lower() #get the input and make it lowercase
if value in list3: #check list for value and then print back a message using that index but from the non-lowercase list
    pos = list3.index(value)
    print "list contains", list2[pos]
else: #if the input doesn't match an item print an error message
    print "error"

ill put this all into some function in my main file once it's working the way i need. Basically I want to change some of the lines in my text file to have valid alternate abreviations and be able to accept those in this and still display the full name back to the user. For example, one of the lines in my secondary text file that has the abbreviations has a line of:

Kog'Maw - kogmaw, kog, km

how can i simplify what I have and add that functionality? I'm not really sure where to start, I'm pretty new to python and programming in general. Thank you for any help you can provide, sorry for such a long post.

Était-ce utile?

La solution

OK, here's a revised answer that assumes there's one file containing names and abbreviations as shown at the beginning of this.

Essentially what it does is make a large lookup table that maps any abbreviation in the file plus the name itself in lowercase to the name at the beginning of each line.

lookup = {}
with open("champions.txt") as f:
    for line in f:
        line = line.rstrip().split('-', 1)
        if not line: continue # skip any blank lines

        name = line[0].strip()
        lookup[name.lower()] = name
        if len(line) == 2:  # any alternative names given?
            for item in line[1].split(','):
                lookup[item.strip()] = name

print 'lookup table:'
for alt_name, real_name in sorted(lookup.items()):
    print '{}: {}'.format(alt_name, real_name)
print

while True:
    print "which champ (Enter to quit): "  # ask user for input
    value = raw_input().lower()  # get the input and make it lowercase
    if not value: break

    real_name = lookup.get(value)
    if real_name:
        print 'found:', value, '-->', real_name
    else:
        print 'error: no match for', value

Autres conseils

First, you should use useful names. So, instead of list2 call it lower_names, etc.

Second, you could replace the in operator and index call by just one index call. If you noticed, a call to some_list.index(item_which_does_not_exist) will raise a valueError saying that the item is not in the list. The most "pythonic" way to do this is by trying to get the index, except if it fails, then you would do something else.

So you could replace the if part by this:

try:
    pos = list3.index(value)
except ValueError:
    print 'error'
else:
    print 'everything is ok. there was no exception raised'
    print 'list contains', list2[pos]

It is often said in the python philosophy that it is better to ask for forgiveness than for permission. :)

Another important thing, and this is only assuming that you want to match a lowercase name to its "real" name, you need here a dictionary. A dictionary maps a key to a value, so what you have here is a case where you want each lowercase name (key) to map to the real name (value). It can be defined this way (I see you are familiar with one liners):

name_map = {item.lower(): item for item in (line.strip() for line in f)}

So, instead of using readlines, you can directly loop through the file. That's extra sugar in Python.

And then, you can do something like: value in name_map or real_name = name_map[value].

As for the extra functionality, I'd go for your second option, which is name - nickname1,nickname2. So what you need to do is: read each line, split by the dash - (or whatever other character that will not be used in the names), then split the second part by the commas to have each name alone. Wrapping up:

name_map = {}
nick_map = {}
for line in f:
    parts = line.strip().split('-')
    name = parts[0].strip()
    nicks = {n.strip(): name for n in parts[1].split(',')}
    name_map[name.lower()] = name
    nick_map.update(nicks)

# To check a name:
if value in name_map:
   # Exact match
elif value in nick_map:
   # Nickname match
else:
   # No Match

You could do the equivalent with try/except/else clauses, but that will make too much nesting, which is not recommended.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top