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)
Related
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
}
I have one class. For that i want to append data to constructor empty list variable. I am trying to append data. But it's not working and throwing error as "NameError: name 'items' is not defined". before this code has been worked.
Here it my code snippet :
class data:
def __init__(self,items=[]):
self.items = items
self.m1(n)
def m1(self,n):
self.n=2
for i in range(self.n):
d = input('enter the values :')
self.items.append(d)
print(self.items)
d=data(items)
here are some issues wrong:
1.) On line 11, items is not defined anywhere before trying to initialize the class, so you end up receiving an error when you call
d=data(items)
2.) On line 4, n is not defined. It is neither passed in along as a parameter with the constructor or defined elsewhere within the constructor block. You will need to define n.
Here is a working version though, with all the variables properly defined:
class data:
def __init__(self, n, items=[]):
self.items = items
self.m1(n)
def m1(self, n):
self.n=2
for i in range(self.n):
d = input('enter the values :')
self.items.append(d)
print(self.items)
items = [1, 5, 7]
d = data(2, items)
class data:
def __init__(self,number,name,list_values=[]):
self.number = int(input('Enter a number :'))
self.name = name
self.list_values = list_values
self.m1()
def m1(self):
for i in range(self.number):
items = input('Enter the values :')
self.list_values.append(items)
print(self.list_values)
list_values= None
d=data('siddarth',list_values)
I’m writing a function that takes in a parent object data and a string inputString that may or may not include dot notation to represent nested objects (i.e. ‘nestedObject.itemA). The function should set the inputString attribute of data to a random string. If the string inputString is a nested object, the function should set the nested object’s value to be a random string. I can’t figure out how to handle this all in a for-loop. I want to do something like this:
split_objects = value.split(“.”)
for item in split_objects:
data.__setattr__(item, get_random_string())
However, in the case of nested objects, the above would set the nested object to be a random string, instead of the field inside. Would someone be able to help me with the syntax to handle both cases? Thanks in advance…
You need to get a reference to data.nestedObject before you can use setattr to change data.nestedObject.itemA.
prefix, suffix = value.rsplit(".",1)
# now prefix is nestedOjbect and suffix is itemA
ref = getattr(data,prefix)
setattr(ref,suffix,get_random_string())
You need to get the reference as many times as there are dots in inputString. So, if you have an arbitrarily deeply nested structure in data
value = "nestedObject.nestedObject2.nestedObject3.itemA"
path, attribute = value.rsplit(".",1)
path = path.split(".")
ref = data
while path:
element, path = path[0], path[1:]
ref = getattr(ref, element)
setattr(ref, attribute, get_random_string())
Here is some example code I to demo a "setField" function I wrote that similar to what you are looking for:
def setField(obj, fieldPath, value):
fields = fieldPath.split(".")
cur = obj
# use all but the last field to traverse the objects
for field in fields[:-1]:
cur = getattr(cur, field)
# use the last field as the property within the object to be overwritten (not traversed)
setattr(cur, fields[-1], value)
# USE CASE EXAMPLE:
class PrintBase:
def dump(self, level=0):
for key, value in vars(self).iteritems():
print " "*(level*4) + key + ":", value
if isinstance(value, PrintBase):
value.dump(level+1)
class BottomObject(PrintBase):
def __init__(self):
self.fieldZ = 'bottomX'
class MiddleObject(PrintBase):
def __init__(self):
self.fieldX = 'middleQ'
self.fieldY = BottomObject()
class TopObject(PrintBase):
def __init__(self):
self.fieldA = 'topA'
self.fieldB = MiddleObject()
top_obj = TopObject()
print "=== BEFORE ==="
top_obj.dump()
print "=== AFTER ==="
setField(top_obj, 'fieldB.fieldY.fieldZ', '!!!! test value !!!!')
top_obj.dump()
And here is the example output:
=== BEFORE ===
fieldB: <__main__.MiddleObject instance at 0x7f5eb1cc6b48>
fieldX: middleQ
fieldY: <__main__.BottomObject instance at 0x7f5eb1cc6b90>
fieldZ: bottomX
fieldA: topA
=== AFTER ===
fieldB: <__main__.MiddleObject instance at 0x7f5eb1cc6b48>
fieldX: middleQ
fieldY: <__main__.BottomObject instance at 0x7f5eb1cc6b90>
fieldZ: !!!! test value !!!!
fieldA: topA
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)
I am trying to write a function which cleans up URLs (strips them of anything like "www.", "http://" etc.) to create a list that I can sort alphabetically.
I have tried to do this by creating a class including a method to detect the term I would like to remove from the URL-string, and remove it. The bit where I am struggling is that I want to add the modified URLs to a new list called new_strings, and then use that new list when I call the method for a second time on a different term, so that step by step I can remove all unwanted elements from the URL-string.
For some reason my current code returns an empty list, and I am also struggling to understand whether new_strings should be passed to __init__ or not? I guess I am a bit confused with global vs. local variables, and some help and explanation would be greatly appreciated. :)
Thanks! Code below.
class URL_Cleaner(object):
def __init__(self, old_strings, new_strings, term):
self.old_strings = old_strings
self.new_strings = new_strings
self.term = term
new_strings = []
def delete_term(self, new_strings):
for self.string in self.old_strings:
if self.term in string:
new_string = string.replace(term, "")
self.new_strings.append(new_string)
else:
self.new_strings.append(string)
return self.new_strings
print "\n" .join(new_strings) #for checking; will be removed later
strings = ["www.google.com", "http://www.google.com", "https://www.google.com"]
new_strings = []
www = URL_Cleaner(strings, new_strings, "www.")
Why are we making a class to do this?
for string in strings:
string.replace("www.","")
Isn't that what you're trying to accomplish?
Regardless the problem is in your class definition. Pay attention to scopes:
class URL_Cleaner(object):
def __init__(self, old_strings, new_strings, term):
"""These are all instance objects"""
self.old_strings = old_strings
self.new_strings = new_strings
self.term = term
new_strings = [] # this is a class object
def delete_term(self, new_strings):
"""You never actually call this function! It never does anything!"""
for self.string in self.old_strings:
if self.term in string:
new_string = string.replace(term, "")
self.new_strings.append(new_string)
else:
self.new_strings.append(string)
return self.new_strings
print "\n" .join(new_strings) #for checking; will be removed later
# this is referring the class object, and will be evaluated when
# the class is defined, NOT when the object is created!
I've commented your code the necessary reasons.... To fix:
class URL_Cleaner(object):
def __init__(self, old_strings):
"""Cleans URL of 'http://www.'"""
self.old_strings = old_strings
cleaned_strings = self.clean_strings()
def clean_strings(self):
"""Clean the strings"""
accumulator = []
for string in self.old_strings:
string = string.replace("http://", "").replace("www.", "")
# this might be better as string = re.sub("http://(?:www.)?", "", string)
# but I'm not going to introduce re yet.
accumulator.append(string)
return accumulator
# this whole function is just:
## return [re.sub("http://(?:www.)?", "", string, flags=re.I) for string in self.old_strings]
# but that's not as readable imo.
You just need to define new_strings as
self.new_strings = []
and remove new_strings argument from the constructor.
The 'new_strings' and 'self.new_strings' are two different lists.