Python adding to dictionary only by key - python

Let's say i have a city (value) and people (key).
1 city can have many people.
(For example.):
Code:
cities = {'Berlin':{'Dan', 'john'},'Tokyo':{'John'}}
city_dict = {}
people = {}
for city in cities:
?
i want to construct a dictionary in python which insert only if a match between keys occurring.
(For example the desired result.):
{'dan' : {'dan':'berlin','dan':'colorado'},'john' : {'john':'berlin','john':'Tokyo'}}
Thanks.

The desired result can't be achieved as dictionaries, by definition, can't contain duplicated keys.
You can, however, do the following (which is somehow close to the output you wanted):
from collections import defaultdict
cities = {'Berlin': {'Dan', 'John'}, 'Tokyo': {'John'}}
output = defaultdict(set)
for city, names in cities.items():
for name in names:
output[name].add(city)
print(output)
# defaultdict(<class 'set'>, {'Dan': {'Berlin'}, 'John': {'Berlin', 'Tokyo'}})

Other option, without dependencies and returning list of cities:
cities = {'Berlin':{'Dan', 'John'},'Tokyo':{'John', 'Paul'}, 'Liverpool':{'John', 'Paul', 'George', 'Ringo'}, 'Colorado':{'Ringo'} }
res = {}
for k, v in cities.items():
for e in v:
res.setdefault(e,[]).append(k)
print(res)
#=> {'Dan': ['Berlin'], 'John': ['Berlin', 'Tokyo', 'Liverpool'], 'Paul': ['Tokyo', 'Liverpool'], 'Ringo': ['Liverpool', 'Colorado'], 'George': ['Liverpool']}

You can't have a dictionary with duplicate keys like #DeepSpace indicated, so for your problem I can suggest you the following alternative.
Use a dictionary with people's name for keys and for value the cities. And so when you want when combine the two for creating a list tuples or so on.
people = {"Dan": ["Berlin","San Francisco"], "Mario": ["Rome"]}
for name, locations in people:
#combine name with single city if needed
for city in locations:
tuple_tmp = (name,city)
#next store it, print it,...
This approach cons are:
You need to process the values
If you have city and and want to retrieve all names in this one is very slow operation.
You can maintain another structure with the inverted relation, but it's memory consuming.

Related

find an item inside a list of dictionaries

Say I have a list of dictionaries.
each dict in the list has 3 elements.
Name, id and status.
list_of_dicts = [{'id':1, 'name':'Alice', 'status':0},{'id':2, 'name':'Bob', 'status':0},{'id':3, 'name':'Robert', 'status':1}]
so I get:
In[20]: print list_of_dicts
Out[20]:
[{'id': 1, 'name': 'Alice', 'status': 0},
{'id': 2, 'name': 'Bob', 'status': 0},
{'id': 3, 'name': 'Robert', 'status': 1}]
If i recieve a name, how can I get its status without iterating on the list?
e.g. I get 'Robert' and I want to output 1. thank you.
for example you can use pandas
import pandas as pd
list_of_dicts = [{'id':1, 'name':'Alice', 'status':0},{'id':2, 'name':'Bob', 'status':0},{'id':3, 'name':'Robert', 'status':1}]
a = pd.DataFrame(list_of_dicts)
a.loc[a['name'] == 'Robert']
and play with dataframes its very fast because write on c++ and easy (like sql queries)
As you found you have to iterate (unless you are able to change your data structure to an enclosing dict) why don't you just do it?
>>> [d['status'] for d in list_of_dicts if d['name']=='Robert']
[1]
Despite this, I recommend considering a map type (like dict) every time you see some 'id' field in a proposed data structure. If it's there you probably want to use it for general identification, instead of carrying dicts around. They can be used for relations also, and transfer easily into a relational database if you need it later.
I don't think you can do what you ask without iterating through the dictionary:
Best case, you'll find someone that suggests you a method that hides the iteration.
If what really concerns you is the speed, you may break your iteration as soon as you find the first valid result:
for iteration, elements in enumerate(list_of_dicts):
if elements['name'] == "Robert":
print "Elements id: ", elements['id']
break
print "Iterations: ", iteration
# OUTPUT: Elements id: 3, Iterations: 1
Note that numbers of iteration may vary, since dictionaries are not indexed, and if you have more "Roberts", only for one the "id" will be printed
It's not possible to do this without iteration.
However, but you can transform you dictionary into a different data structure, such as a dictionary where names are the keys:
new_dict = {person["name"]: {k: v for k, v in person.items() if k != "name"} for person in list_of_dicts}
Then you can get the status like so:
new_dict["Robert"]["status"]
# 1
Additionally, as #tobias_k mentions in the comments, you can keep the internal dictionary the same:
{person["name"]: person for person in list_of_dicts}
The only issue with the above approaches is that it can't handle multiple names. You can instead add the unique id into the key to differentiate between names:
new_dict = {(person["name"], person["id"]): person["status"] for person in list_of_dicts}
Which can be called like this:
new_dict["Robert", 3]
# 1
Even though it takes extra computation(only once) to create these data structures, the lookups afterwards will be O(1), instead of iterating the list every time when you want to search a name.
Your list_of_dicts cannot be reached without a loop so for your desire your list should be modified a little like 1 dict and many lists in it:
list_of_dicts_modified = {'name':['Alice', 'Bob', 'Robert'],'id':[1, 2, 3], 'status': [0, 0, 1]}
index = list_of_dicts_modified['name'].index(input().strip())
print('Name: {0} ID: {1} Status: {2}'.format(list_of_dicts_modified['name'][index], list_of_dicts_modified['id'][index], list_of_dicts_modified['status'][index]))
Output:
C:\Users\Documents>py test.py
Alice
Name: Alice ID: 1 Status: 0

Python - Create a dictionary from two lists with list name as key and list elements as values

I am a complete newbie to python and coding as well.
I have 2 lists. Name=['John','Ravi','Sam'] and Age=[23,45,34]. How do i create a dictionary with Name and Age as keys and dictionary values from lists' elements. Resulting dictionary would look like
d={'Name':['John','Ravi','Sam'],'Age':[23,45,34])
I tried zip and fromkeys, but that doesn't work. Any help on this would be highly appreciated.
You can't do this dynamically, because there's no way to get from a value (lists in your case) to the names (note the plural) that refer to it.
Like Aran-Fey already commented, you must hardcode the keys via
d = {'Name': Name, 'Age': Age}
If the names in Name and the ages in Age correspond, why don't you create a direct mapping?
>>> name_to_age = dict(zip(Name, Age))
>>> name_to_age
{'John': 23, 'Ravi': 45, 'Sam': 34}
>>> name_to_age['Ravi']
45

How do I turn list values into an array with an index that matches the other dic values?

Hoping someone can help me out. I've spent the past couple hours trying to solve this, and fair warning, I'm still fairly new to python.
This is a repost of a question I recently deleted. I've misinterpreted my code in the last example.The correct example is:
I have a dictionary, with a list that looks similar to:
dic = [
{
'name': 'john',
'items': ['pants_1', 'shirt_2','socks_3']
},
{
'name': 'bob',
items: ['jacket_1', 'hat_1']
}
]
I'm using .append for both 'name', and 'items', which adds the dic values into two new lists:
for x in dic:
dic_name.append(dic['name'])
dic_items.append(dic['items'])
I need to split the item value using '_' as the delimiter, so I've also split the values by doing:
name, items = [i if i is None else i.split('_')[0] for i in dic_name],
[if i is None else i.split('_')[0] for i in chain(*dic_items)])
None is used in case there is no value. This provides me with a new list for name, items, with the delimiter used. Disregard the fact that I used '_' split for names in this example.
When I use this, the index for name, and item no longer match. Do i need to create the listed items in an array to match the name index, and if so, how?
Ideally, I want name[0] (which is john), to also match items[0] (as an array of the items in the list, so pants, shirt, socks). This way when I refer to index 0 for name, it also grabs all the values for items as index 0. The same thing regarding the index used for bob [1], which should match his items with the same index.
#avinash-raj, thanks for your patience, as I've had to update my question to reflect more closely to the code I'm working with.
I'm reading a little bit between the lines but are you trying to just collapse the list and get rid of the field names, e.g.:
>>> dic = [{'name': 'john', 'items':['pants_1','shirt_2','socks_3']},
{'name': 'bob', 'items':['jacket_1','hat_1']}]
>>> data = {d['name']: dict(i.split('_') for i in d['items']) for d in dic}
>>> data
{'bob': {'hat': '1', 'jacket': '1'},
'john': {'pants': '1', 'shirt': '2', 'socks': '3'}}
Now the data is directly related vs. indirectly related via a common index into 2 lists. If you want the dictionary split out you can always
>>> dic_name, dic_items = zip(*data.items())
>>> dic_name
('bob', 'john')
>>> dic_items
({'hat': '1', 'jacket': '1'}, {'pants': '1', 'shirt': '2', 'socks': '3'})
You need a list of dictionaries because the duplicate keys name and items are overwritten:
items = [[i.split('_')[0] for i in d['items']] for d in your_list]
names = [d['name'] for d in your_list] # then grab names from list
Alternatively, you can do this in one line with the built-in zip method and generators, like so:
names, items = zip(*((i['name'], [j.split('_')[0] for j in i['items']]) for i in dic))
From Looping Techniques in the Tutorial.
for name, items in div.items():
names.append(name)
items.append(item)
That will work if your dict is structured
{'name':[item1]}
In the loop body of
for x in dic:
dic_name.append(dic['name'])
dic_items.append(dic['items'])
you'll probably want to access x (to which the items in dic will be assigned in turn) rather than dic.

How to sort one multiarray dict based on another array in python 2.7

I have some data(in array) which I want to sort based(Priority) on another dict
Example
refList = ['INDIA', 'CHINA','USA']
list = { 'Country': [], 'Reps' : []}
list['Country'].append('CHINA')
list['Reps'].append('Xuan Fo')
list['Country'].append('CHINA')
list['Reps'].append('Chan Li')
list['Country'].append('USA')
list['Reps'].append('Jhon Dugg')
list['Country'].append('USA')
list['Reps'].append('Michael Bevan')
list['Country'].append('INDIA')
list['Reps'].append('Rahul Kartik')
I am trying to sort the list based on the refList given country name.
I saw something like
newlist = sorted(list['Country'], key=lambda k: refList)
But it does not give me the desired output..
Any ideas? I know I am doing something wrong but I don't know how to....
I know I can iterate with
for key in refList:
and compare each entry and make a new list but for a large input list it is taking very long time to go through.
My Python doesn't have
from collections import OrderedDict
The actual list(different name obviously) has data appended the way I showed.. I don't have control over it I just have the full list. I only showed in code to give idea how they are in the tree.
This is how it may look like
{'Country': ['CHINA', 'CHINA', 'USA', 'USA', 'INDIA'], 'Reps': ['Xuan Fo', 'Chan Li', 'Jhon Dugg', 'Michael Bevan', 'Rahul Kartik']}
And I want to reorder it as (with my relist priority)
{'Country': ['INDIA','CHINA', 'CHINA', 'USA', 'USA'], 'Reps': ['Rahul Kartik','Xuan Fo', 'Chan Li', 'Jhon Dugg', 'Michael Bevan']}
Number one, don't use list as a variable name because it is a builtin function. I would merge your two seperate lists into a list of (rep name, country) pairs using the zip function.
d = list(zip(l['Reps'], l['Country']))
To sort the list, you need to look up where the country occurs in refList using the index method.
d.sort(key=lambda pair: refList.index(pair[1]))
To convert back into two lists, use zip with the splat operator:
l['Reps'], l['Country'] = zip(*d)

Finding the dictionary a key value comes from

Lets say we have a list of dictionaries, ranging in the thousands. Every dictionary has the exact same keys, but different values.
Is there any way to lookup which dictionary a key value comes from, and then access different key values from that same dictionary?
For example, say you have a list containing every person in a large city, dictionary format, like so:
people_in_city = [
{'name': 'Bob Jang',
'age': 45,
'sex': 'male'},
{'name': 'Barb Esau',
'age': 56,
'sex': 'female'},
etc.
etc.
Now, you want to lookup the age of Bob Jang, but you only have his name. Is there anyway to get his corresponding age using this format?
There's no fast way to do this in Python. I'd suggest something like:
def get_dict_from_key(list_of_dicts, key, value):
return next((d for d in list_of_dicts if d[key] == value))
result_d = get_dict_from_key(dicts, 'name', 'Bob Jang')
result_d['age']
That said, this is the kind of thing that relational databases are made for! Learn SQL and use it :)
I would suggest looking at a database as Adam Smith suggested. Though I would also like to suggest looking at a class. That would go something like:
class Person():
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
people_in_city = []
def add_person(name, age, gender
people_in_city=people_in_city):
people_in_city.append(Person(name, age, gender))
def find_by_name(name):
for person in people_in_city:
if person.name == name:
return person
Not the most elegant way, but it gets the job done, plus you can add more information and not have have to change the nature of your search function. So lets say you find dear 'Bob Jang', and you realize that you want to know that job he is doing (assuming you coded that into the class). You just do:
person_of_interest = find_by_name('Bob Jang')
person_of_interest.job
person_of_interest.age
Note that this only gives the LAST found value of the name, and not everyone with that name. Other methods will have to be employed for that. This method also means that you are holding all the information in a list, and that might get slow as the list grows. That is why databases would work better as your list grows.
And as a bonus, it is possible to create each person in parallel.
Try this,
provided_name = 'some name'
persons_list_with_name = [person_info in person_info in people_in_city if person_info['name'] == provided_name]
for person_info in persons_list_with_name:
print person_info['name'], person_info['age']
(age,) = [v['age' ]for (k,v) in people_in_city.iteritems() if v['name']=="Bob Jang"]
people_in_city = [
{'name': 'Bob Jang',
'age': 45,
'sex': 'male'},
{'name': 'Barb Esau',
'age': 56,
'sex': 'female'}]
v = age or name sex etc..
for i in people_in_city:
if v in i.values():
print i
There is a python package called bidict that can do this. It provides a two-way dict, which allows you to get the key from the value or the value from the key. An example from the documentation:
>>> element_by_symbol = bidict(H='hydrogen')
>>> element_by_symbol['H'] # forward mapping works just like with dict
'hydrogen'
>>> element_by_symbol[:'hydrogen'] # use slice for the inverse mapping
'H'

Categories

Resources