简体   繁体   中英

Python 2.7: list concatenation for class objects within a dictionary

This is for an assignment (albeit turned utterly on its head so that I still have to think through any solutions provided and actually learn something here...) and I've spent the last three hours doing various tutorials around the web and thumbing through the Python manual, Daniweb, and here, and just cannot figure out how to synthesize these concepts.

I have a bunch of input coming from a text file (let's say it's the below) from which the first item on each line is going to turn into the key for a dictionary, and the latter three items go into a class 'Fruit' that ends up describing the things, as you'd imagine.

lemon?yellow?sour?not
lemon?yellow?sour?yes
orange?orange?sweet?yes
grape?purple?sweet?yes

I'd like the key "lemon" created from this file to return the descriptors "yellow sour not" AND "yellow sour yes" as a list.

class Fruit(object):
'''Describes fruits'''
    def __init__(self,color,flavor,tasty):
        self.color = color
        self.flavor = flavor
        self.tasty = tasty

    def getColor(self): return self.color
    def getFlavor(self): return self.flavor
    def getTasty(self): return self.tasty
    def description(self): return self.color,self.flavor,self.tasty

fruity = {}

for line in inputFile:   
    n,c,f,t = line.split('?')
    indFruit = fruit(c,f,t)
    fruity[n] = [fruit.description]

All this has worked so far, except of course that the second time the file hits the key "lemon" it overwrites the "yellow sour not" with "yellow sour yes" (in other words as written it seems to be doing everything it's supposed to do.)

So I'm working on a way to handle that lemon problem. I tried:

fruity = {}
fruitlist = []

for line in inputFile:   
    n,c,f,t = line.split('?')
    indFruit = fruit(c,f,t)
    fruity[n] = fruitlist.append(indFruit)

which produces

{(lemon): none, (orange): none, (grape): none}

and then

fruity = {}
fruitlist = []

for line in inputFile:   
    n,c,f,t = line.split('?')
    indFruit = fruit(c,f,t)
    fruitlist.append(indFruit)
    fruity[n] = fruitlist

which is a bit of an overachiever as it produces:

{(lemon): [(yellow, sour, not),(yellow,sour,yes),(orange,sweet,yes),(grape,sweet,yes)}

I'm having trouble figuring out how to make it do what I want, which is to display:

{(lemon): [(yellow, sour, not),(yellow,sour,yes)], (orange): [(orange, sweet, yes)]}
and so on.

Thanks in advance!

Instead of a dictionary mapping keywords such as "lemon" to a list, map it to a set and have ("yellow", "sour", "not") or ("yellow", "sour", "yes") as a tuple instead of your Fruit class and add them to the set object.

The set will ensure that you only retain unique items. If later you find that you need to have them as a list for some reason, then simply call list(my_dict["lemon"])

If you are insistent on using your custom class, then look into making your Fruit class hashable by defining __hash__ method in your class. You could do this in your class by simply aggregating the values ("yellow" etc.) into a tuple and returning the hash of that tuple when __hash__ is called. Just a quick and dirty method. You might want to research for better ways to create hashes for whatever values you might be storing if they are not necessarily strings such as "Yellow" etc. and could be more complex data types.

Note that the values added to a set cannot be a list because lists are not hashable. That is why I suggested a tuple (or defining a __hash__ method for your class).

Also, you might find the setdefault() and get() method in a dictionary object useful. I recommend looking them up in the python documentation or google for them.

It's your last line:

fruity[n] = fruitlist

This is setting the value of fruity[n] to the entire list. I'm guessing you'd want to do something like using a default dict, so you can get an individual list for each fruit (you could also use setdefault , but why not be more readable?)

from collections import defaultdict
fruity = defaultdict(lambda : []) # new list for each item

#... at the end of your forloop
fruity[n].append(indFruit)

Check out the docs on defaultdict for more. It's also dead simple to create your own defaultdict or switch your last line to:

 fruity.setdefault(n, [])
 fruity[n].append(indFruit)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM