import a list into a dictionary value Python - python

I am trying to import this list item from the main function:
character1 = Character("Conan the Barbarian")
for test_item in ["sword", "sausage", "plate armor", "sausage", "sausage"]:
character1.give_item(test_item)
I am using class and in the class there is those methods to save the list to the character
class Character:
def __init__(self, character):
self.__character = character
self.__dct = {}
def give_item(self, items):
self.__dct[self.__character] = items
def printout(self):
for characters in self.__dct:
print(f'Name:', characters)
for items in self.__dct.keys():
print(self.__dct[self.__character])
my output is printing only the last entry from the list, seems like the entries being overwritten. But I can't really figure why.
my output
Name: Conan the Barbarian
sausage
I want my output to be:
Name: Conan the Barbarian
plate armor
sausage
sword

This is because you're reusing your key. Every time, you assign to self.__dict[self.__character]
Your loop for items in self.__dict.keys()) is oddly written. items here is actually a list of keys, and will therefore only run once, when in actuality you want to run it # items times.
Instead, you could use a list (or set):
def __init__(self, character):
self.__character = character
self.__dct = {}
self.__dct[self.__character] = []
def printout(self):
for characters in self.__dct:
print(f'Name:', characters)
for item in self.__dct[self.__character]:
print(item)

It seems like your self.__dct[self.__character] = items line uses the [self.__character] as the key to append to your dict. In a Python Dictionnary, you can just add your list as easy as writing the key and putting the list as the value like so:
self.__dct = {
"name" = character_name,
"items" = list_of_items
}

Related

how to print a list that is in a dictionary, as a string in python? And how to edit the list's elements?

I have a class that has a dictionary attribute. The dictionary has song titles as its key and a list containing artist, genre and playCount like this:
class library:
def __init__(self,library):
self.library={}
def addSong(self,title,artist,genre,playCount):
self.library[title]=[artist,genre,playCount]
The playCount is an integer. How do I add a 1 to the playCount element without changing any of the other elements. Do I make a new function for it or can I do it without making a function?. Also how can I make a function to print the keys and values of the dictionary as a string like this:
artist, title (genre), playCount
IIUC, you just want to increment playCount every time you pass an existing title to addSong, right?
You can put in an if-else condition in addSong to check if title is in self.library or not and if it exists, then just increment the last element of value of key title by playCount.
Also, to print, it's just a matter of assigning items in their correct positions:
class library:
def __init__(self):
self.library = {}
def addSong(self, title, artist, genre, playCount=1):
if title in self.library:
self.library[title][-1] += playCount
else:
self.library[title] = [artist, genre, playCount]
def get_song_data(self, title):
if title in self.library:
x = self.library[title] + [title]
return "{0}, {3} ({1}), {2}".format(*x)
lib = library()
Output:
lib.addSong('Easy on Me','Adele','ballad',10)
print(lib.get_song_data('Easy on Me')) # Adele, Easy on Me (ballad), 10
lib.addSong('Easy on Me','Adele','ballad',2)
print(lib.get_song_data('Easy on Me')) # Adele, Easy on Me (ballad), 12
lib.addSong('Easy on Me','Adele','ballad')
print(lib.get_song_data('Easy on Me')) # Adele, Easy on Me (ballad), 13

Creating Python Class for Transforming Non-Alphanumeric Characters to Dash

I am trying to create a class in Python that transforms non-alphanumeric characters to a dash for a list of strings.
For example, we have the following list: inventory_list_1 = ['ABCDE : CE ; CUSTOMER : Account Number; New Sales', 'JKLEH : SC ; CLIENT : Record Number; old Sales']
And we want the end result to be: inventory_list_2 = ['ABCDE-CE-CUSTOMER-AccountNumber-NewSales', 'JKLEH-SC-CLIENT-RecordNumber-oldSales']
I tried to create the following class, but it did not work. How does one create a Python class to transform non-alphanumeric characters to a dash for a list of strings? And how does one execute the class to transform inventory_list_1 to inventory_list_2?
class clean_data:
def __init__(self, list):
self.list = list
def transform_data(self):
for string_item in self.list:
return re.sub('[^0-9a-zA-Z]+', '-', string_item)
print (clean_data(inventory_list_1))
Any function can execute return statement only once. In your approach, you are trying to traverse all the list items and then returning each modified item. But as mentioned above, only one return statement will get executed, and hence only the first modified element is being returned instead of the whole list. To return all the modified elements, create a new list appending all the modified element and then return the new list from the function.
def class clean_data:
def __init__(self, list1):
self.list1 = list1
def transform_data(self):
retList =[]
for string_item in self.list1:
retList.append(re.sub('[^0-9a-zA-Z]+', '-', string_item))
return(retList)
inventory_list_1 = ['ABCDE : CE ; CUSTOMER : Account Number; New Sales', 'JKLEH : SC ; CLIENT : Record Number; old Sales']
print (clean_data(inventory_list_1).transform_data())
You should define __repr__ for your class.
import re
class clean_data:
def __init__(self, list):
self.list = list
def transform_data(self):
temp = []
for string_item in self.list:
temp.append(re.sub('[^0-9a-zA-Z]+', '-', string_item))
return temp
def __repr__(self):
return str(self.list)
inventory_list_1 = ['ABCDE : CE ; CUSTOMER : Account Number; New Sales', 'JKLEH : SC ; CLIENT : Record Number; old Sales']
temp = clean_data(inventory_list_1)
inventory_list_2 = temp.transform_data()
print(inventory_list_2)

Refactoring For-Loops in Python

I am currently working on an iTunes data program that's cycling constantly through a user's library to get statistics about one's library.
returns
I have a few code snippets like these:
def numArtist(self):
num = 0
for song in self.allSongs:
tempList = []
if song.artist not in tempList:
tempList.append(song.artist)
num += 1
return num
def getAlbumNames(self):
albums = []
for song in self.allSongs:
if song.album not in albums:
albums.append(song.album)
return albums
Where the main for loop body is repeated:
for song in self.allSongs: # same for-loop condition
# different for-loop body
Is there a way to refactor methods like these, where I have the same for loop conditions but with different body definitions?
I have a quite a few methods with the same for-loop, so I'd like to find a way to decrease the complexity and redundancy of my code.
Just for reference, all Song objects have attributes - artist, album (name),genre, etc - that I'm using to get my data.
Use set comprehensions and len to simplify each of them:
def numArtist(self):
return len({song.artist for song in self.allSongs})
def getAlbumNames(self):
return {song.album for song in self.allSongs}
To make it more generic, you could write a method that takes a lambda and use that to filter the property out of each song:
def uniqueProps(self, fxn):
return {fxn(song) for song in self.allSongs}
def getAlbumNames(self):
return self.uniqueProps(lambda song: song.album)
You can use set comprehensions for both snippets, if that counts as a valid "For-Loop refactoring":
artist_count = len({song.artist for song in self.allSongs})
album_names = set({song.album for song in self.allSongs})
Generic version using getattr
get_values = lambda objs, attr: {getattr(obj, attr) for obj in objs
attributes = 'artist', 'album'
values = [get_values(self.allSongs, name) for name in attributes]
artists, albums = values
artist_count = len(artists)
Generic version using lambda
get_artist = lambda song: song.artist
get_album = lambda song: song.album
getters = get_artist, get_album
values = [
{func(song) for song in self.allSongs}
for getter in getters
]
artists, albums = values
artist_count = len(artists)
Generic version using property
# If `song` is an instance of the `Song` class and both `artist` and
# `album` are properties defined on the class, it's also possible to
# directly use the property getter (`property.fget`) to avoid defining
# the lambdas manually:
get_artist = Song.artist.fget
get_album = Song.album.fget
... # <same as above>
If the contents of your allSongs list are immutable - which I suspect they are - you can convert your lists to sets and back to lists again - or use set comprehension - to get rid of duplicates. Then your functions can be greatly simplified like so:
def numArtist(self):
return len({song.artist for sing in self.allSongs})
def getAlbumNames(self):
return list({song.album for song in self.allSongs})
If you're not sure if the song objects are mutable or not, try this out anyway. If they're mutable objects you'll get an exception like:
TypeError: unhashable type: ...
You could try to create the generators, that produces the value of song attributes. Let me give you an example:
def gen_attr(songs, attr_name):
for song in songs:
yield getattr(song, attr_name)
class Song(object):
def __init__(self, name, artist):
self.name = name
self.artist = artist
class Album(object):
def __init__(self, songs_list):
self.songs_list = songs_list
def allSongs(self):
return self.songs_list
s = Song('Ahoy', 'Pirate')
s1 = Song('Bye', 'My Son')
s2 = Song('Ahoy', 'Captain')
a = Album([s, s1])
Now if you want to get all of the song names, u can use:
song_names = list(gen_attr(a.allSongs(), 'name'))
print(song_names) # ['Ahoy', 'Bye', 'Ahoy']
For non-repeated song names you would use:
song_names = list(set(gen_attr(a.allSongs(), 'name')))
print(song_names) # ['Ahoy', 'Bye']
To count the non-repeated artists names, you would use:
artists = len(set(gen_attr(a.allSongs(), 'artist')))
And to create the list of artists, just go for:
artists = list(gen_attr(a.allSongs(), 'artist'))
print(artists) # ['Pirate', 'My Son', 'Captain']

List iterate inside class method causing infinite loop in python

Hello Friends I'm a newbie to Python and trying to implement some sample code using Classes in Python. I could implement using individual functions but when I'm trying to integrate via class I'm ending up in infinite loop.
Here is the snippet of code and logic I'm reading a file where contents are like as follows:
File input.txt contents
fruit apple
animal cat
vehicle car
My final aim is to get output as dictionary of contents with key and value like below dict and later I want to search with keys and do processing.
{'fruit': 'apple', 'animal': 'cat', 'vehicle':'car'}
class FileHandler:
def __init__(self, dbf):
self.logger = logging.getLogger('fileHandler')
self.thefile = open(dbf, 'r')
print(self.thefile)
def __enter__(self):
return self
def __exit__(self,type,value,traceback):
self.thefile.close()
with FileHandler(dbf='input.txt') as fh:
config = [line.strip() for line in (fh.thefile.readlines())]
Here is the class definition:
class GetExtract:
def __init__(self, config_list=None, config_dict=None):
if (config_list, config_dict) is None:
config_list = []
config_dict = {}
self.config_list = config_list
self.config_dict = config_dict
def assign_sig(self, listin):
self.config_list = listin
#for item in listin:
# self.config_list = listin.extend(item.split())
#print("final dict is \n", self.config_list) ## break items into list
## Map adjacent items as key and value
#for index, kvalue in enumerate(self.config_list):
# if index %2 == 0:
# self.config_dict[kvalue] = self.config_list[index+1]
# return self.config_dict ## create a mapping inside dict
xtemp = GetExtract()
xtemp.assign_sig(config)
When I try to iterate using the for loop inside the class it goes into an infinite loop which I have commented in the above code for.
Please advise me how to achieve my aim using classes.
for item in listin:
self.config_list = listin.extend(item.split())
The object you are looping over (in this case listin) is being modified whithin the loop. Never do that.

Calling Object inside of List

class MySong:
_songTitle = "Song Title"
_artistName = "Artist Name"
_likeIndicator = -1
def setTitleAndArtist(self, songTitle, artistName):
self._songTitle = songTitle
self._artistName = artistName
def setLike(self, likeIndicator):
self._likeIndicator = likeIndicator
def undoSetLike(self, songTitle):
Null
def getTitle(self):
return self._songTitle
def getArtist(self):
return self._artistName
def getLikeIndicator(self):
return self._likeIndicator
class MyPlaylist:
_mySongs = []
def add(self, song):
self._mySongs.append(song)
def showTitles(self):
index = 0
titlesList = []
while index != len(self._mySongs):
titlesList.append(self._mySongs[index].getTitle())
index = index + 1
return titlesList
def remove(self):
remindex = 0
while remindex != len(self._mySongs):
if (self._mySongs[index].getTitle()) == remChoice :
return("Song FOUND debug!")
self._mySongs.remove(index)
else:
remindex = remindex + 1
return("Song NOT FOUND debug!")
def getMySong(self):
Null
There is a list of song objects inside of _mySongs = []. I'm trying to remove one, based on the title variable of that object.
In a separate (unshown) part of the program, the user is asked to enter the title of the song they want removed as a string. This is saved as remChoice.
I'm not entirely sure how to remove the song based on the title.
I've tried for a while to get it going, obviously we find the index of the song in the list by matching it to the title (by calling the getTitle method), then removing that index when it's found.
This isn't working. Where am I going wrong?
If you want to delete an item from a list knowing it's index use:
del xs[i]
Where i is the index. (e.g: Your song's index based on your search).
list.remove() is used for removing a matching element form the list not the "ith" item.
You might also find that a list is not a suitable data structure here? Perhaps you could try storing key/value pairs in a dict. e.g:
my_songs = {}
my_aongs["My Song Title"] = MySong(title, description, length)
You can later delete songs via their keys:
del my_songs["My Song Title"]
where titles are your keys. This saves you from doing O(n) searching.
Update:
Your .remove() method should look more like the following:
def remove(self, title):
for i, song in enumerate(self._mySongs):
if song.getTitle() == title:
del self._mySongs[i]
return
print("Song not found!")
Here we're using list's iteration protocol by using a for x in xs: rather than using a while loop and doing manual bookkeeping. The builtin function enumerate() is also used to give us an index into the list we're iterating over (i.e: it's position in the sequence).
try
self._mySongs.remove(title)
That should work.
(Or from another object: replace self by whatever your object name is)

Categories