Insert only unique objects into list - python

I have queryset of people:
people = Person.objects.all()
and I have a list un_people = [] - meaning a list of people with unique name.
So, there can be more than one person with the same name. i want to filter for this and then insert into list so that list only contains person objects with unique name.
I tried:
for person in people:
if person.name in un_people:
#... ?
but in list, there are objects, not names. how can I check for objects with same name and then insert into list?

Use a dict to do the uniqueness, then take the values, eg:
uniq_names = {person.name:person for person in people}
uniq_people = uniq_names.values() # use list(unique_names.values()) for Py 3.x

You can use set data structure:
un_people = set(people)
If your elements are not hashable as, JonClemens, suggests you can build a list of names first:
un_people = set([p.name for p in people])

Related

Edit list element in multilist - Python

I am using python 3.x, I have the following problem, using the keyboard the user enters certain data and fills N lists to create a contact list, then in a list I collect all the data of the lists, I need to modify the data of each list, (I already have it, I modify the data of a list with a specific value using a for) Example, Names list, I modify Andrew's name, but in the Contacts list, there is all Andrew's information (phone, mail, etc), but I just need to modify in the Contacts list, the value of Andrew
I have all this list:
names = []
surnames = []
phones = []
emails = []
addresses = []
ages = []
salaries = []
genres = []
contacts = []
# and use the append to add the data into the contacts list
contacts.append ([names, surnames, phone numbers, emails, addresses, ages, salaries, genders])
Then I update the info of one contact
search = input(Fore.LIGHTBLUE_EX + "Type the name of the contact you want update: ")
for i in range(len(names)):
if (names[i] == search):
try:
names[i] = input(Fore.MAGENTA + "Type the New name: ")
names[i] = nombres[i].replace(" ", "")
if names[i].isalpha() == True:
print(Fore.GREEN + "Already saved, congrats.")
pause= input(Fore.LIGHTGREEN_EX + "Press enter to exit")
But I dont know how to update the name in the List of contacts.
When you call contacts.append(), you add a list of lists to a list, so your contacts list will look something like this:
contacts = [[[names[0], names[1], ...], [...], [...]]]
It's unnecessary to have a list of one item nested in another list, so I would just call contacts.append() and pass each list (names, surnames, etc.) to the method, which allows for easier indexing.
Since the list names would be the first item in the list contacts (contacts[0]), you could do one of two things (there may be more, but these are off the top of my head):
Reassign the specific index to a new value, using nested-list indexing (contacts[0][0] = "updated name" would update the first item of the names list to "update name")
Reassign the entire nested list to a new list (contacts[0] = new_name_list would reassign contacts[0], formerly the names list, to new_name_list)
On a side note: In this case, I would recommend dictionaries over lists, as it will be easier to keep track of what is being reassigned/modified.
contacts = {
"names": names,
"surnames": surnames,
...
}
Doing this will make it more clear which list your are referring to; contacts[0] doesn't give much information, but contacts["names"] informs readers that you are referring to the names list. This is solely for cleaner code; there isn't much difference in functionality.

Dynamically create instances of a class python

I'm new in python and I'm trying to dynamically create new instances in a class. So let me give you an example, if I have a class like this:
class Person(object):
def __init__(self, name, age, job):
self.name = name
self.age = age
self.job = job
As far as I know, for each new instance I have to insert, I would have to declare a variable and attach it to the person object, something like this:
variable = Person(name, age, job)
Is there a way in which I can dynamically do this? Lets suppose that I have a dictionary like this:
persons_database = {
'id' : ['name', age, 'job'], .....
}
Can I create a piece of code that can iterate over this db and automatically create new instances in the Person class?
Just iterate over the dictionary using a for loop.
people = []
for id in persons_database:
info = persons_database[id]
people.append(Person(info[0], info[1], info[2]))
Then the List people will have Person objects with the data from your persons_database dictionary
If you need to get the Person object from the original id you can use a dictionary to store the Person objects and can quickly find the correct Person.
people = {}
for id, data in persons_database.items():
people[id] = Person(data[0], data[1], data[2])
Then you can get the person you want from his/her id by doing people[id]. So to increment a person with id = 1's age you would do people[1].increment_age()
------ Slightly more advanced material below ----------------
Some people have mentioned using list/dictionary comprehensions to achieve what you want. Comprehensions would be slightly more efficient and more pythonic, but a little more difficult to understand if you are new to programming/python
As a dictionary comprehension the second piece of code would be people = {id: Person(*data) for id, data in persons_database.items()}
And just so nothing here goes unexplained... The * before a List in python unpacks the List as separate items in the sequential order of the list, so for a List l of length n, *l would evaluate to l[0], l[1], ... , l[n-2], l[n-1]
Sure, a simple list comprehension should do the trick:
people = [Person(*persons_database[pid]) for pid in persons_database]
This just loops through each key (id) in the person database and creates a person instance by passing through the list of attributes for that id directly as args to the Person() constructor.

Django: get users' IDs with field

I have a model, for example:
class Person(models.Model):
name =
surname =
city =
cars =
I need to get a list of the IDs (primary key auto-set) of the 5 users with the highest number of "cars" with a specific name.
I thought I could do something like:
list = Person.objects.filter(name=name,)('-reputation')[5].id
To get a list of the 5 users with the highest number you can use:
list = Person.objects.filter(name=name).order_by('-reputation')[:5]
to get the ID of each you can use for loop:
for user in list:
userID = user.id
You seem to have missed out the call to order_by.
Person.objects.filter(name=name).order_by('-reputation')[5].id
Using the values_list queryset function can reduce this to a single simple line:
Person.objects.values_list('id', flat=True).filter(name=name).order_by('-reputation')[:5]
and will avoid needing to loop.

Django, filter and group query results by a field

I have this working but I'm sure there must be a better method
The context is a movie/television app so there are titles (movies/tv) and people who act in each, many to many relationship.
I have a "titlepeople" model with information such as:
id, people_fk, title_fk, role_title
On movies where a cast member has alot of roles I need to display their information like:
Tom Hanks: Gardener, Police Man #1, Another Role #4
Is there anyway I can optimize the below way of doing this so the code isn't so lengthy?
cast_unique = list()
for person in cast:
#if not in the unique list, add them
if person.people not in [p.people for p in cast_unique]:
cast_unique.append(person)
else:
# if in the list, append the role information
if person.role_title:
for c in cast_unique:
if c.people == person.people:
# append role info
c.role_title = '{0} / {1}'.format(c.role_title, person.role_title)
Thanks
You should change cast_unique to be a dictionary where you use the cast member as the key. This will allow much greater performance because you won't have to iterate the cast_unique iterable.
Also, your use a list comprehension in the if person.people not in [p.people for p in cast_unique]: requires an entire list to be create of people for every iteration for the test; which, could use a lot of memory plus there's no way to short circuit the list comprehension when a match occurs. Still a dictionary is a much better data type to use for this situation.
cast_unique = {}
for person in cast:
if person.people not in cast_unique:
cast_unique[person.people] = person
else:
cast_unique[person.people].role_title = '{0} / {1}'.format(cast_unique[person.people].role_title, person.role_title)

List of objects with a unique attribute

I have a list of objects that each have a specific attribute. That attribute is not unique, and I would like to end up with a list of the objects that is a subset of the entire list such that all of the specific attributes is a unique set.
For example, if I have four objects:
object1.thing = 1
object2.thing = 2
object3.thing = 3
object4.thing = 2
I would want to end up with either
[object1, object2, object3]
or
[object1, object3, object4]
The exact objects that wind up in the final list are not important, only that a list of their specific attribute is unique.
EDIT: To clarify, essentially what I want is a set that is keyed off of that specific attribute.
You can use a list comprehension and set:
objects = (object1,object2,object3,object4)
seen = set()
unique = [obj for obj in objects if obj.thing not in seen and not seen.add(obj.thing)]
The above code is equivalent to:
seen = set()
unique = []
for obj in objects:
if obj.thing not in seen:
unique.append(obj)
seen.add(obj.thing)
You could create a dict whose key is the object's thing and values are the objects themselves.
d = {}
for obj in object_list:
d[obj.thing] = obj
desired_list = d.values()

Categories

Resources