Edit list element in multilist - Python - 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.

Related

How can I add two or more elements to a list from a single input in Python?

What my script is doing now is adding elements to a list. For example, if the user types "JO", I will add "John" to the list. What I want to do now is that, if the user types "2 JO", I add two elements to the list: "John" and "John".
This is how the database looks like now:
Sample database copy.png
This is the code now:
import pandas
data = pandas.read_excel("Sample database copy.xlsx")
name = dict(zip(data["Abbreviation"],data["Name"]))
list1 = []
incoming_msg = input(Please type what you want to add: )
list1.append(name[incoming_msg])
I need to do it all from the same input, I cannot ask separately for quantity and abbreviation. I wanted to know if there is any library that can do this somehow easily because I am a beginner coder. If there is no library but you have any idea how I could solve it, it would be awesome as well.
Thank you so much in advance!
you can use string.split() to split the string by space into a list then use the first element to multiply a list that contains the value from the dictionary and increment it to the result list. see the code
name = dict(zip(data["Abbreviation"],data["Name"]))
list1 = []
incoming_msg = input('Please type what you want to add: ')
incoming_msg = incoming_msg.split() # split the string by space
if len(incoming_msg) == 2: # if there are two elements in the list (number and name)
list1 += [name[incoming_msg[1]]] * int(incoming_msg[0])
else:
list1.append(name[incoming_msg[0]])

Python: Nested List Inside Dictionary?

I'm currently stuck with this output of a nested list when trying to append the list as the definition of my dictionary.
I know this is probably more code than I should include, but I figured it's helpful to show more than less.
class Account:
accountInfo = {} #ex. ID : 5FE19C (hexadecimal ID's)
def __init__(self):
choice = raw_input("Would you like to login or signup?\n")
if choice.lower() == "login":
self.login()
elif choice.lower() == "signup":
print "Great! Fill in the following."
self.signup()
else:
self.__init__()
def signup(self):
import random
accountID = '%010x' % random.randrange(16**10) # 10 digit hexadecimal ID generator
personalInfo = []
self.accountInfo[accountID] = []
firstName = raw_input("First Name: ")
lastName = raw_input("Last Name: ")
email = raw_input("E-Mail: ")
password = raw_input("Password: ")
birthdate = raw_input("DOB (DD/MM/YYYY): ")
alias = raw_input("Username/Alias: ")
personalInfo.append(firstName)
personalInfo.append(lastName)
personalInfo.append(email)
personalInfo.append(password)
personalInfo.append(birthdate)
personalInfo.append(alias)
for i in range(1):
self.accountInfo[accountID].append(personalInfo)
#creates an unwanted nested list, but the output is correct
print self.accountInfo
I don't understand why I'm getting the output of a nested list in my dictionary. The contents of the dictionary are correct, but it's just that unwanted and unnecessary nested list.
output:
>>> {'6de7bcf201': [['firstName', 'lastName', 'email', 'password', 'birthdate', 'alias']]}
personalInfo = [] # PersonalInfo is a list
# skipped
self.accountInfo[accountID].append(personalInfo) # add list to the list
This is similar to
main = []
p_info = []
main.append(p_info) # result would be main = [[]]
If you want to have just a dict inside list, change personalInfo to {}
that would requare to change personalInfo.append to personalInfo[x] = y
I think this is pretty straight forward:
personalInfo is a list. You append items to it and get something like [..,..,..]. You initiate the value of self.accountInfo[accountID] also as a list. Then you append your first list to the second list, giving you a list of lists.
Instead of self.accountInfo[accountID].append(personalInfo) try self.accountInfo[accountID] = personalInfo
Welcome! A couple of things:
Imports should generally be at the top of a file. For your signup
function, the import random should be at the top.
Your __init__ shouldn't be called again on a class. __init__ is considered the "constructor" of the class - as such it should generally be called once. Consider putting your raw_input section in another function and call that twice.
Print is a function, not a statement (your last line)
To answer your question, you have a nested list because you are making two lists. You're first building up personalInfo and then appending that item to the empty list you made for accountInfo you can have a single-level list if you just set self.accountInfo[accountID] =personalInfo`.
personalInfo is a list and self.accountInfo[accountID] is another list.
With self.accountInfo[accountID].append(personalInfo) you are injecting one inside the other.
You can do self.accountInfo[accountID] = personalInfo
And what's the point of for i in range(1)? It's not looping at all!
I can't test right now but:.
Replace self.accountInfo[accountID] = [] with self.accountInfo[accountID] = personalInfo. And delete for i in range(1): self.accountInfo[accountID].append(personalInfo)

Convert User Input into a List name

Here is what I have so far:
TotalLists=int(input("How many Lists are you making?"))
TotalListsBackup=TotalLists
Lists=[]
while TotalLists>0:
ListName=input("What would you like to call List Number "+str(TotalLists))
Lists.append(ListName)
TotalLists=TotalLists-1
TotalLists=TotalListsBackup-1
while TotalLists>=0:
Lists[TotalLists] #I would like to create actual lists out of the list names at this step but I dont know how...
TotalLists=TotalLists-1
TotalLists=TotalListsBackup-1
print("Here are your Lists: ")
while TotalLists>=0:
print(Lists[TotalLists])
TotalLists=TotalLists-1
I want to be able to:
create a List out of the List Names
The code to be able to make as many lists as the user wants to without a cap
For example, I want to input: Grocery,
The code will create a list Called Grocery
Solutions I have thought of:
Arrays? (I have never used them, I am very new to Python Programming and I dont know too much)
Lists of Lists? (Not sure how to do that. Looked it up, but didn't get a straight answer)
Using Variables, Creating a list with a name like:
List1[]
and have varible called:
List1Name=input("What would you like to call list 1?")
I do not know how to create an infinite number of lists using this way though.
If you have any questions please ask, for I know I am not good at explaining.
It's interesting that you have tagged the question "dictionary" but didn't mention that in your post. Did somebody tell you to use a dictionary? That's exactly what you should be doing, like this (assume TotalLists is already defined):
d = {}
for _ in range(TotalLists): # The same loop you have now
ListName = input("whatever...")
d[ListName] = []
At the end of this you have a dictionary d containing keys that are the user-entered names, and values that are empty lists. The number of dictionary entries is TotalLists. I'm ignoring the possibility that the user will enter the same name twice.
You're solving an XY problem. There's no need to ask for the number of lists in advance. I would recommend using a dictionary:
>>> lists = {}
>>> while 1:
... newlist = input("Name of new list (leave blank to stop)? ")
... if newlist:
... lists[newlist] = []
... while 1:
... newitem = input("Next item? ")
... if newitem:
... lists[newlist].append(newitem)
... else:
... break
... else:
... break
...
Name of new list (leave blank to stop)? groceries
Next item? apples
Next item? bananas
Next item?
Name of new list (leave blank to stop)? books
Next item? the bible
Next item? harry potter
Next item?
Name of new list (leave blank to stop)?
>>> lists
{'groceries': ['apples', 'bananas'], 'books': ['the bible', 'harry potter']}

Insert only unique objects into list

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])

Combining two lists and sorting through reference to dictionary Python

I have (what seems to me is) a pretty convoluted problem. I'm going to try to be as succinct as possible - though in order to understand the issue fully, you might have to click on my profile and look at the (only other) two questions I've posted on StackOverflow. In short: I have two lists -- one is comprised of email strings that contain a facility name, and a date of incident. The other is comprised of the facility ids for each email (I use one of the following regex functions to get this list). I've used Regex to be able to search each string for these pieces of information. The 3 Regex functions are:
def find_facility_name(incident):
pattern = re.compile(r'Subject:.*?for\s(.+?)\n')
findPat1 = re.search(pattern, incident)
facility_name = findPat1.group(1)
return facility_name
def find_date_of_incident(incident):
pattern = re.compile(r'Date of Incident:\s(.+?)\n')
findPat2 = re.search(pattern, incident)
incident_date = findPat2.group(1)
return incident_date
def find_facility_id(incident):
pattern = re.compile('(\d{3})\n')
findPat3 = re.search(pattern, incident)
f_id = findPat3.group(1)
return f_id
I also have a dictionary that is formatted like this:
d = {'001' : 'Facility #1', '002' : 'Another Facility'...etc.}
I'm trying to COMBINE the two lists and sort by the Key values in the dictionary, followed by the Date of Incident. Since the key values are attached to the facility name, this should automatically caused emails from the same facilities to be grouped together. In order to do that, I've tried to use these two functions:
def get_facility_ids(incident_list):
'''(lst) -> lst
Return a new list from incident_list that inserts the facility IDs from the
get_facilities dictionary into each incident.
'''
f_id = []
for incident in incident_list:
find_facility_name(incident)
for k in d:
if find_facility_name(incident) == d[k]:
f_id.append(k)
return f_id
id_list = get_facility_ids(incident_list)
def combine_lists(L1, L2):
combo_list = []
for i in range(len(L1)):
combo_list.append(L1[i] + L2[i])
return combo_list
combination = combine_lists(id_list, incident_list)
def get_sort_key(incident):
'''(str) -> tup
Return a tuple from incident containing the facility id as the first
value and the date of the incident as the second value.
'''
return (find_facility_id(incident), find_date_of_incident(incident))
final_list = sorted(combination, key=get_sort_key)
Here is an example of what my input might be and the desired output:
d = {'001' : 'Facility #1', '002' : 'Another Facility'...etc.}
input: first_list = ['email_1', 'email_2', etc.]
first output: next_list = ['facility_id_for_1+email_1', 'facility_id_for_2 + email_2', etc.]
DESIRED OUTPUT: FINAL_LIST = sorted(next_list, key=facility_id, date of incident)
The only problem is, the key values are not matching properly with what's found in each individual email string. Some DO, others are completely random. I have no idea why this is happening, but I have a feeling it has something to do with the way I'm combining the two lists. Can anyone help this lowly n00b? Thanks!!!
First off, I would suggest reversing your ID-to-name dictionary. Looking up a value by key is very fast but finding a key by value is very slow.
rd = { name: id_num for id_num, name in d.items() }
Then your first function can be replaced by a list comprehension:
id_list = [rd[find_facility_name(incident)] for incident in incident_list]
This might also expose why you're getting messed up values in your results. If an incident has a facility name that's not in your dictionary, this code will raise a KeyError (whereas your old function would just skip it).
Your combine function is very similar to Python's built in zip function. I'd replace it with:
combination = [id+incident for id, incident in zip(id_list, incident_list)]
However, since you're building the first list from the second one, it might make sense to build the combined version directly, rather than making separate lists and then combining them in a separate step. Here's an update to the list comprehension above that goes right to the combination result:
combination = [rd[find_facility_name(incident)] + incident
for incident in incident_list]
To do the sort, you can use the ID string that we just prepended to the email message, rather than parsing to find the ID again:
combination.sort(key=lambda x: (x[0:3], get_date_of_incident(x)))
The 3 in the slice is based off of your example of "001" and "002" as the id values. If the actual ids are longer or shorter you'll need to adjust that.
So, here is what I think is going on. Please correct me if possible.
The 'incident_list' is a list of email strings. You go in and find the facility names in each email because you have an external dictionary that has the (key:value)=(facility id: facility name). From the dictionary, you can extract the facility id in this 'id_list'.
You combine the lists so that you get a list of strings [facility id + email,...]
Then you want it to sort by a tuple( facility id, date of incidence ).
It looks like you are searching for the facility id and the facility name twice. You can skip a step if they are the same. Then, the best way is to do it all at once with tuples:
incident_list = ['email1', 'email2',...]
unsorted_list = []
for email in incident list:
id = find_facility_id(email)
date = find_date_of_incident(email)
mytuple = ( id, date, id + email )
unsorted_list.append(mytuple)
final_list = sorted(unsorted_list, key=lambda mytup:(mytup[0], mytup[1]))
Then you get an easy list of tuples sorted by first element (id as a string), and then second element (date as a string). If you just need a list of strings ( id + email ), then you need a list with the last element of each tuple part
FINALLIST = [ tup[-1] for tup in final_list ]

Categories

Resources