python nested for loop iteration - python

I would like the inner for loop to give me one value and goes on to the next iteration for each outer loop. Appreciate your responds.
Currently the result:
Personal NameJohn
Personal NamePeter
Personal Name123456
ID #John
ID #Peter
ID #123456
Emergency contactJohn
Emergency contactPeter
Emergency contact123456
Result should just be:
ID #123456
Personal NameJohn
Emergency contactPeter
employees={'ID #','Personal Name','Emergency contact'}
excel={'123456',
'John',
'Peter'}
for key in employees:
for value in excel:
print(key + value)

Use zip to iterate over two objects at the same time.
note: you are using sets (created using {"set", "values"}) here. Sets have no order, so you should use lists (created using ["list", "values"]) instead.
for key, value in zip(employees, excel):
print(key, value)

You can use zip after changing the type of your input data. Sets order their original content, thus producing incorrect pairings:
employees=['ID #','Personal Name','Emergency contact']
excel=['123456', 'John','Peter']
new_data = [a+b for a, b in zip(employees, excel)]
Output:
['ID #123456', 'Personal NameJohn', 'Emergency contactPeter']

First of all, use square brackets [] instead of curly brackets {}. Then you could use zip() (see other answers) or use something very basic like this:
for i in range(len(employees)):
print(employees[i], excel[i])

Related

Finding highest value in a dictionary

I'm new to programming and currently taking a CSC 110 class. Our assignment is to create a bunch functions that do all sorts of things with some data that is given. I have taken all that data and put it into a dictionary but I'm having some trouble getting the data I want out of it.
Here is my problem:
I have a dictionary that stores a bunch of countries followed by a list that includes their population and GDP. Formatted something like this
{'country': [population, GDP], ...}
My task is to loop through this and find the country with the highest population or GDP then print:
'The country with the highest population is ' + highCountry+\
' with a population of ' + format(highPop, ',.0f')+'.')
In order to do this I wrote this function (this one is specifically for highest population but they all look about the same).
def highestPop(worldInfo):
highPop = worldInfo[next(iter(worldInfo))][0] #Grabs first countries Population
highCountry = next(iter(worldInfo))#Grabs first country in worldInfo
for k,v in worldInfo.items():
if v[0] > highPop:
highPop = v[0]
highCountry = k
return highPop,highCountry
While this is working for me I gotta think there is an easier way to do this. Also I'm not 100% sure how [next(iter(worldInfo))] works. Does this just grab the first value it sees?
Thanks for your help in advance!
Edit: Sorry I guess I wasn't clear. I need to pass the countries population but also the countries name. So I can print both of them in my main function.
I think you're looking for this:
max(worldInfo.items(), key=lambda x: x[1][0])
This will return both the country name and its info. For instance:
('france', [100, 22])
The max() function can work on python "iterables" which is a fancy word for anything that can be cycled or looped through. Thus it cycles or loops through the thing you put into it and spits out the item that's the highest.
But how does it judge which tuple is highest? Which is higher: France or Germany? You have to specify a key (some specification for how to judge each item). The key=lambda etc specifies a function that given an item (x), judge that item based on x[1][0]. In this instance if the item is ('france', [100, 22]) then x[1][0] is 100. So the x[1][0] of each item is compared and the item with the highest one is returned.
The next() and iter() functions are for python iterators. For example:
mytuple = ("apple", "banana", "cherry")
myit = iter(mytuple)
print(next(myit)) #=> apple
print(next(myit)) #=> banana
print(next(myit)) #=> cherry
Use the max() function, like so:
max(item[0] for item in county_dict.values()) #use item[1] for GDP!
Also try storing the values not in a list ([a, b]) but in a tuple ((a, b)).
Edit: Like iamanigeeit said in the comments, this works to give you the country name as well:
max(data[0], country for country, data in country_dict.items())
An efficient solution to get the key with the highest value: you can use the max function this way:
highCountry = max(worldInfo, key=lambda k: worldInfo[k][0])
The key argument is a function that specifies what values you want to use to determine the max.max(data[0], country for country, data in country_dict.items())
And obviously :
highPop = worldInfo[highCountry][0]

Creating a dict containing a sub-dict as the new value with the index as the key

I have a dictionary currently setup as
{'name': 'firm', 'name':'firm', etc},
Where keys are analyst names and values are analyst firms.
I am trying to create a new dictionary where the new values are the old k,v pairs and the associated key is simply the index (1, 2, 3, 4, etc).
Current code is below:
num_analysts = len(analysts.keys())
for k,v in analysts.items():
analysts_dict = dict.fromkeys(range(num_analysts), [k,v])
Current result
Each numeric key is getting given the same value (old k,v pair). What is wrong with my expression?
You can enumerate the items and convert them to a dictionary. However, dictionaries, in general, are not ordered. This means that the keys may be assigned essentially randomly.
dict(enumerate(analysts.items(), 1))
#{1: ('name1', 'firm1'), 2: ('name2', 'firm2')}
Enumerate and dictionary comprehension for this
d = {'name1': 'firm1', 'name2': 'firm2'}
d2 = {idx: '{}, {}'.format(item, d[item]) for idx, item in enumerate(d, start = 1)}
{1: 'name1, firm1', 2: 'name2, firm2'}
There are already effective answer posted by others. So I may just put the reason why your own solution does't work properly. It may caused by lazy binding. There are good resource on: http://quickinsights.io/python/python-closures-and-late-binding/
Because late binding will literally pick up the last one in dictionary you created. But this last one is not "virtually last one", it is determined by the OS. (Other people already give some explanation on dict data-structure.)
For each time you run in python command line the result may change. If you put the code in .py file, For each time you run in IDE, the result will be same.(always the last one in dict)
During each iteration, analysts_dict is assigned value based on the result of dict.items().
However, you should use comprehension to generate the final result in one line,
E.g. [{i: e} for i, e in enumerate(analysts.items())]
analysts = {
"a": 13,
"b": 123,
"c": 1234
}
num_analysts = len(analysts.keys())
analysts_dict = [{i: e} for i, e in enumerate(analysts.items())]
print(analysts_dict)
>> [{0: ('a', 13)}, {1: ('b', 123)}, {2: ('c', 1234)}]
This code
for k,v in analysts.items():
analysts_dict = dict.fromkeys(range(num_analysts), [k,v])
loops over the original dict and on each loop iteration it creates a new dict using the range numbers as the keys. By the way, every item in that dict shares a reference to a single [k, v] list object. That's generally a bad idea. You should only use an immutable object (eg None, a number, or a string) as the value arg to the dict.fromkeys method. The purpose of the method is to allow you to create a dict with a simple default value for the keys you supply, you can't use it to make a dict with lists as the values if you want those lists to be separate lists.
The new dict object is bound to the name analysts_dict. On the next loop iteration, a new dict is created and bound to that name, replacing the one just created on the previous loop, and the replaced dict is destroyed.
So you end up with an analysts_dict containing a bunch of references to the final [k, v] pair read from the original dict.
To get your desired result, you should use DYZ's code, which I won't repeat here. Note that it stores the old name & firm info in tuples, which is better than using lists for this application.

Using append to get data from a nested list

Currently my code is like this:
.append("Last Name {}, First Name {} Stats: {}".format(result["L_Name"], result["F_Name"], result["Stats"]))
this code works but the output isn't exactly the ones I want the code to display.
the problem is that the Stats has another list
L_Name: Doe
F_Name: John
Contribution:
Month
Value
Returns
is there a way to just pick out only the Value from the Stats by just adding or changing something in my append?
specifically in this part?
, result["Stats"]))
If you are only after one value of Stats, you can get the value at a certain index. Assuming Value is at index 1 and Stats is a standard Python list:
, result["Stats"][1]))
Notice that you can access the items of the JSON structure in the format string itself. This is clearer than using positional arguments if the format string is very complicated. Additionally, you can pass the whole dictionary into format_map:
l.append("Last Name {L_Name}, First Name {F_Name} Stats: {Stats[Value]}"
.format_map(result))
(In Python 2, format_map doesn't exist, use format(**result) instead.
In the future please consider posting working code only so we can reproduce your issue. I am going to assume result['stats'] is a dictionary and the bulleted list are key:value pairs.
You can access the "Contribution" key of your result["Stats"] dictionary which results in list. You can then slice the second element of the list with [1].
_.append("Last Name {}, First Name {} Stats: {}".format(
result["L_Name"],
result["F_Name"],
result["Stats"]["Contribution"][1]))
This assumes result['stats'] looks like:
result['stats'] = {
'L_Name': 'Doe',
'F_Name': 'John',
'Contribution': [Month, Value, Returns]}
Thanks everyone I was able to get a hint from your answers
result["Stats"]["Contribution"][1]
worked well for me

Django turn lists into one list

I want to put this data into one list so i can sort it by timestamp. I tried itertools chain but that didn't really work.
Thank you for your help :)
I'm very bad at making clear what i want to do so im sorry upfront if this takes some explaning.
If i try a chain i get the value back like this.
I want to display it on the html page like this :
date, name , rating, text (newline)
likes comments
Which would work the way i did it but if i want to sort it by time, it wouldn't work so i tried to think of a way to make it into a sortable list. Which can be displayed. Is that understandable ?
['Eva Simia', 'Peter Alexander', {'scale': 5, 'value': 5}, {'scale': 5, 'value': 5}, 1, 0, 1, 0]
it should look like this:
['Peter Alexander, scale:5, value:5, 1,0]
['Eva Simia, scale:5, value:5, 1,0]
for i in user:
name.append(i['name'])
for i in next_level:
rating_values.append(i['rating'])
for i in comment_values:
comments_count.append(i['count'])
for i in likes_values:
likes_count.append(i['count'])
for s in rating_values:
ratings.append(s['value'])
for s in date:
ratings.append(s['date'])
ab = itertools.chain([name], [rating_values],
[comments_count], [likes_values],
[comment_values], [date])
list(ab)
Updated after clarification:
The problem as I understand it:
You have a dataset that is split into several lists, one list per field.
Every list has the records in the same order. That is, user[x]'s rating value is necessarily rating_values[x].
You need to merge that information into a single list of composite items. You'd use zip() for that:
merged = zip(user, next_level, comment_values, likes_values, rating_values, date)
# merged is now [(user[0], next_level[0], comment_values[0], ...),
# (user[1], next_level[1], comment_values[1], ...),
# ...]
From there, you can simply sort your list using sorted():
result = sorted(merged, key=lambda i: (i[5], i[0]))
The key argument must be a function. It is given each item in the list once, and must return the key that will be used to compare items. Here, we build a short function on the fly, that returns the date and username, effectively telling things will be sorted, first by date and if dates are equal, then by username.
[Past answer about itertools.chain, before the clarification]
ab = list(itertools.chain(
(i['name'] for i in user),
(i['rating'] for i in next_level),
(i['count'] for i in comment_values),
(i['count'] for i in likes_values),
(i['value'] for i in rating_values),
(i['date'] for i in date),
))
The point of using itertools.chain is usually to avoid needless copies and intermediary objects. To do that, you want to pass it iterators.
chain will return an iterator that will iterate through each of the given iterators, one at a time, moving to the next iterator when current stops.
Note every iterator has to be wrapped in parentheses, else python will complain. Do not make it square brackets, at it would cause an intermediary list to be built.
You can join list by simply using +.
l = name + rating_values + comments_count + ...
date, rating_values,likes_values,comment_values,next_level,user = (list(t) for t in zip(*sorted(zip(date, rating_values,likes_values,comment_values,next_level,user))))

How to Re-arrange items in a Python Dictionary during For Loop?

I am building a Python dictionary from a table in Excel. It's a Category:Name relationship. So, the first column in the spreadsheet is a category and the second column is the name of a file:
Forests - Tree Type
Forests - Soil Type
Administrative - Cities
Administrative - Buildings
Mineral - Gold
Mineral - Platinum
Water - Watershed
Water - Rivers
Water - Lakes
Water - Streams
and so on...
I use this code to build the dictionary:
layerListDict = dict()
for row in arcpy.SearchCursor(xls):
# Set condition to pull out the Name field in the xls file.
# LayerList being the list of all the 'Name' from the 'Name' column built earlier in the script
if str(row.getValue("Name")).rstrip() in layerList:
# Determine if the category item is in the dictionary as a key already. If so, then append the Name to the list of values associated with the category
if row.getValue("Category") in layerListDict:
layerListDict[row.getValue("Category")].append(str(row.getValue("Name")))
# if not, create a new category key and add the associated Name value to it
else:
layerListDict[row.getValue("Category")] = [str(row.getValue("Name"))]
So, now I have a dictionary with Category as the key and a list of Names as the values:
{u'Forests': ['Tree Type', 'Soil Type'], u'Administrative': ['Cities', 'Buildings'], u'Mineral': ['Gold', 'Platinum'], u'Water': ['Watershed', 'Rivers', 'Lakes', 'Streams']}
I can now iterate over the sorted dictionary by key:
for k,v in sorted(layerListDict.iteritems()):
print k, v
PROBLEM: What I would like to do is to iterate over the sorted dictionary with one caveat...I wanted to have the 'Mineral' key to be the very first key and then have the rest of the keys print out in alphabetical order like this:
Mineral ['Gold', 'Platinum']
Administrative ['Cities', 'Buildings']
Forests ['Tree Type', 'Soil Type']
Water ['Watershed', 'Rivers', 'Lakes', 'Streams']
Can anyone suggest how I can accomplish this?
I tried to set a variable to a sorted list, but it returns as a python list and I cannot iterate over the Python list by a key value pair anymore.
List2 = sorted(layerListDict.iteritems())
[u'Forests':['Tree Type', 'Soil Type'], u'Administrative': ['Cities', 'Buildings'], u'Mineral': ['Gold', 'Platinum'], u'Water': ['Watershed', 'Rivers', 'Lakes', 'Streams']]
print "Mineral", layerListDict.pop("Mineral")
for k, v in sorted(layerListDict.iteritems()):
print k, v
If you don't want to modify layerListDict:
print "Mineral", layerListDict["Mineral"]
for k, v in sorted(layerListDict.iteritems()):
if k != "Mineral":
print k, v
An overly general solution:
import itertools
first = 'Mineral'
for k, v in itertools.chain([(first, layersListDict[first])],
((k,v) for (k,v) in layerListDict.iteritems() if k != first)):
print k, v
or closer to my original incorrect solution:
for k, layersListDict[k] in itertools.chain((first,),
(k for k in layerListDict
if k != first)):
print k, v
If you're just looking to print the key-value pairs, then the other solutions get the job done quite well. If you're looking for the resulting dictionary to have a certain order so that you can perform other operations on it, you should look into the OrderedDict class:
https://docs.python.org/2/library/collections.html#collections.OrderedDict
Objects are stored in the order that they are inserted. In your case, you would do something similar to the other answers first to define the order:
dict_tuples = sorted(layerListDict.items())
ordered_tuples = [("Mineral", layerListDict["Mineral"],)]
ordered_tuples += [(k, v,) for k, v in dict_tuples if k != "Mineral"]
ordered_dict = collections.OrderedDict(ordered_tuples) #assumes import happened above
Now you can do whatever you want with ordered_dict (careful with deleting then reinserting, see the link above). Don't know if that helps you more than some of the other answers (which are all pretty great!).
EDIT: Whoops, my recollection of the update behavior of OrderedDicts was a bit faulty. Fixed above. Also streamlined the code a little. You could potentially generate the tuples in your first for loop and then put them in the OrderedDict, too.
EDIT 2: Forgot that tuples are naturally sorted by the first element (thanks John Y), removed the unnecessary key param in the sorted() call.
Keep a list of keys in the order you want to iterate over the map. Then iterate through the list, using the values as keys into the map.
Actually, after seeing the other solutions, I like chepner's answer with itertools.chain() better, especially if the list of keys is large, because mine will move things around in the list too much.
# sort the keys
keyList = sorted(keys(layerListDict))
# remove 'Mineral' from it's place
del keyList[keyList.index('Mineral')]
# Put it in the beginning
keyList = ['Mineral'] + keyList
# Iterate
for k in keyList:
for v in layerListDict[k]:
print k, v
Second shot at an answer. This is pretty different from my original, and makes some possibly wrong assertions, but I like the feel of it a lot better. Since you're able to determine all of the values in the "name" column (layerList), I'm going to assume you can do the same for the "categories" column. This code assumes you've placed your categories (including "Mineral") into an unsorted list called categories, and replaces the original code:
categories.sort()
categories = ["Mineral"] + [cat for cat in categories if cat != "Mineral"]
# Insert the categories into our dict with placeholder lists that we can append to
layerListDict = collections.OrderedDict([(cat, [],) for cat in categories])
for row in arcpy.SearchCursor(xls):
if str(row.getValue("Name")).rstrip() in layerList:
layerListDict[row.getValue("Category")].append(str(row.getValue("Name")))
Now you can just iterate over layerListDict.items().

Categories