Compare attributes of objects inside a list? - python

I'm trying to sort a list of textMessage objects into several lists.
Each textMessage has three fields - the address of the sender, the time it was sent, and the body of the message.
I have listOfContacts which contains Contact objects. Each Contact object has two fields - the name of the contact and a listOfTexts from that contact. The listOfTexts is filled with a list of textMessage objects.
I'm having trouble with the function that does the sorting. Given a list of texts, I want it to add a new Contact object to listOfContacts if the contact isn't yet in the list. Otherwise I want to append the textMessage object to the listOfTexts inside of the Contact inside of listOfContacts
I'm having a hard time seeing if the contact is already present inside of listOfContacts
def sortObjectArray(textArray):
listOfContacts = []
emptyList = []
for text in TextArray: # For each text in the sorted array
if text.address in listOfContacts.name: # if the text's address is in list of contacts
addText(text) # add the text to the list of texts in contact's class
else:
listOfContacts.append(Contact(text.get("address"), emptyList) #if address not in list of contacts, construct one with an empty list of texts.
I thought that if text.address in listOfContacts.name should check if any Contact with a name field of n exists in listOfContacts, where n is the sender of the text message.
Am I going about this the wrong way?

A list object doesn't have the properties of the contained objects. Consider the following absolutely valid python list:
list_ = ["ah", 12, object(), lambda honey: str(honey) ]
and tell me why
if "ah" in list_.lower():
should have a defined behaviour.
What you want to do is make the objects in your list hashable by their names, and build a set out of them.
EDIT: hashable means you implement the __hash__ function, which in this case might just be
class Contact(object):
def __hash__(self):
return self.name.__hash__
Also, you should define an __eq__ function (eq like equality), so that python can check whether two contacts are equal:
def __eq__(self,other):
return self.name==other.name
As soon as you have done that, you can use the set type, which is just like the list type, but only allows a single "equal" object. That makes a lot of sense for a contact list! After having done that, you can just create a dummy Contact object and check whether it's in the set.
That, or you'll simply have to iterate over all of them:
if any(text.address == cont.name for contact in listOfContacts):
EDIT: that just checks if any of contacts has a name property that is equal to your text.address.

The first problem that you will likely encounter is that listOfContacts will not have a name attribute, since it is a list and not a Contact object. You can create a new list of contact names that will be used to check if the address exists already.
def sortObjectArray(textArray):
listOfContacts = []
contact_names = []
...
for text in TextArray: # For each text in the sorted array
if text.address in contact_names: # if the text's address is in list of contacts
...
else:
contact_names.append(text.address)
listOfContacts.append(Contact(text.get("address"), emptyList) #if address not in list of contacts, construct one with an empty list of texts.

Related

hashing elements of objects in a list to create quick lookup [python]

I have similar needs to this c# question. I have a list of classes. The class contains a list of synonyms for the name of an object. I would like to set up a data structure where I can input one of the synonyms and any class object with that synonym returns. Preferably the objects in the list won't be copied but referenced in memory. The class object can be immutable as its values won't change. Here is some dummy code to explain my situation:
class MyObject:
def __init__(self,name):
self.name = name # name of an object such as "cup"
self.synonyms = get_synonyms(name) # returns a list of strings (i.e.) [ "coffee cup", "mug", "dixie cup", . . . ]
my_objects = create_1000_MyObjects() # returns a list of 1000 of the above classes
new_data_structure = ?
objects_containing_synonym = new_data_structure.find_objects("cofee cup") # would return any object in the above list that holds "coffee cup" in its list of synonyms, so would return object cup
It's worth noting there might be more than one object needing to be returned. I want to use some hash solution like a dictionary so that lookup is fast.
A dict mapping one synonym to a list of objects will do. collections.defaultdict eliminates the need to first test the dictionary to see if a key exists.
import collections
new_data_structure = defaultdict(list)
my_object = create the object
new_data_structure.update((synonym, my_object) for synonym in my_object.synonyms)
all_coffee_cup_objects = new_data_structure["coffee_cups"]

How to iterate over different ids levels using weakref in kivy

I have this sequence of ids.
self.ids.cuarta_pantalla.ids.container.ids.pre_1.ids.Si
In this case, container has 70 different ids [from pre_1 until pre_70] and each pre_(x) has three different ids [Si, MasMenos, No] that correspondes to a group of CheckBoxes.
If I want to know the state of a single checkbox using its atribute value, I'm forced to write all the statement like this.
self.ids.cuarta_pantalla.ids.container.ids.pre_1.ids.Si.value.
So, How can I iterate over the ids?
I've tried using square brackets self.ids.cuarta_pantalla.ids.container.ids['pre_1'] but it returns something with which I can't call any method.
Print with Square brackets: <weakref at 0x125F7118; to 'BoxLayout' at 0x125F30D0>
Print with dot notation: <kivy.uix.boxlayout.BoxLayout object at 0x125F30D0>
This is the way I've created the objects:
for idx in range(70):
BoxContainer = BoxLayout()
# Repeat this two more times with MasMenos and No
check1 = CheckBox(group= f"p_{idx+1}")
BoxContainer.add_widget(check1)
BoxContainer.ids['Si'] = weakref.ref(check1)
#Adding the BoxContainer with CheckBoxes to the container
self.ids.cuarta_pantalla.ids.container.add_widget(BoxContainer)
self.ids.cuarta_pantalla.ids.container.ids[f'pre_{idx+1}'] = weakref.ref(BoxContainer)
There is no need to use weakref, every time that add_widget is used, an Observable List called children into the object in which was added the other one will contain the reference of that added object.
For example:
IDlist = self.ids.cuarta_pantalla.ids.container.children
The variable IDlist can be iterated to get each reference where you can call any method of that particular object

How to see if a certain class exists in a list

I have a class, user, that has an attribute metadata.
metadata is a list of objects, each with different classes, for example:
user.metatada = [Employee(), Student(), OtherClass()]
In an update script, I need to check, if a certain type exists in a list, like so:
if type(Employee()) in user.metadata:
replace user.metadata[indexOfThatEmployee] with new Employee()
else:
user.metadata.append(new Employee())
is there anyway to easily to check if a certain type exists in a list?
Got it.
test = [Employee()]
if any(isinstance(x, Employee) for x in user.metadata):
user.metadata = [x for x in user.metadata if not isinstance(x, Employee)] + test
else:
user.metadata = user.metadata + test
So this will check if there exists an object in the list that is an instance of the Employee class, if so, filter the list of the existing Employee object and add in the new one, if it doesn't exist, just add it in.

Variable that returns complete string inside list

I have this code:
topic = "test4"
topics = sns.get_all_topics()
topicsList = topics['ListTopicsResponse']['ListTopicsResult']['Topics']
topicsListNames = [t['TopicArn'] for t in topicsList]
That returns a list:
[u'arn:aws:sns:us-east-1:10:test4', u'arn:aws:sns:us-east-1:11:test7']
What Im trying now is create a variable that returns the complete string relative to the topic variable.
I have the variable topic = "test4", and I want to have a variable topicResult that returns u'arn:aws:sns:us-east-1:10:test4.
The string relative to topic its not always in list 1st position.
Do you know how to do this?
topicResult = " ".join([t['TopicArn'] for t in topicsList if t['TopicArn'].endswith(topic)])
This will check the strings in the list to see if the topic variable is the end of one of the strings. " ".join() gives you a string, but if you want to keep a list of the strings that end with topic, you can get rid of it. If topic won't always be at the end of the string, you can just check if topicis inside the string.
topicResult = " ".join([t['TopicArn'] for t in topicsList if topic in t['TopicArn']])
You could use intention lists, with a check statement in, but I think built-in filter will be faster:
topicsListNames = filter(lambda item: item['TopicArn'].endswith(topic), topicsList)
Basically, this line take the topicsList, then takes only the items item for which item['TopicArn'].endswith(topic) is True, ie. the items whose 'TopicArn' element ends with the reference of the topic variable. Finally, all these "good" items are returned, and topicsListNames references them.

Python: Function that searches through a dictionary in a dictionary

I have a question that goes like this
Write the contract, docstring and implementation for a function findActor that takes a movie title and a character's name and returns the actor/actress that played the given character in the given movie. If the given movie or the given character is not found, it prints out an error message and returns an empty string
I have already done the following functions that will be of assistance for doing this. And myIMDb is a global dictionary, set to an empty dic to start
def addMovie (title, charList, actList):
"""The function addMovie takes a title of the movie, a list of characters,
and a list of actors. (The order of characters and actors match one
another.) The function addMovie adds a pair to myIMDb. The key is the title
of the movie while the value is a dictionary that matches characters to
actors"""
dict2 = {}
for i in range (0, len(charList)):
dict2 [charList[i]] = actList[i]
myIMDb[len(myIMDb)] = {title: dict2}
return myIMDb
def listMovies():
"""returns a list of titles of all the movies in the global variable myIMDb"""
titles = []
for i in range (len(myIMDb)):
titles.append((list(myIMDb[i].keys())))
return titles
Here's where I'm having problems. When I want to write the findActor function I'm getting nothing to return. I'm not finished with the function but I'm thinking that i've done something fundamentally wrong. I feel like I'm going down the wrong road and I'm getting more and more lost the more I write. Here's what I have so for. Any suggestions for how to right this sinking ship would be appreciated.
def findActor(title, name):
myIMDb = {}
for i in range (len(myIMDb)):
if title == myIMDb[i].keys():
if name == myIMDb[i].get(name):
return myIMDb[i].get(name)
else:
return "Error: No Movie found"
You need to populate your myIMDB dictionary in findActor before you use it.
In addition, I'd suggest mapping myIMDB directly from the title of the move to characters. In other words, instead of doing myIMDb[len(myIMDb)] = {title: dict2} in your addMoive, you should just do myIMDb[title] = dict2.
This way, when you need to look up the title and character, you can simply do:
def findActor(title, name):
if title in myIMDb:
if name in myIMDb[title]:
return myIMDb[title][name]
return "Error: No movie found"
The first thing to learn, programming in any language, is to reduce your task to sub-tasks. Here, why not start first with creating just a dictionary of roles and actors for a single movie. If you can't do that, then you won't be able to complete the full project.
After you work on that, maybe everything else will fall into place.
Warning: in the real world, occasionally more than one actor may play a role - for example - a role in which a child matures into adulthood. But that likely is not in your spec.

Categories