Python Dictionaries: Different way to iterate through a dict - python

I am searching for a different way to access every key in a dictionary within a for loop. Underneath, there is an example code, where I iterate through a dictionary and access every key with the help of a counter and a if statement. Is there another way to access the keys, without a counter or an if statement?
def string_to_dict(csv):
dict = []
tmp = csv.splitlines()
for i in tmp:
tmp_dict = {"vorname" : "none", "nachname" : "none", "email" : "none"};
tmp_i= i.split(",")
counter = 0;
for si in tmp_i:
if counter ==0:
tmp_dict["vorname"] = si
counter =counter + 1
elif counter == 1:
tmp_dict["nachname"] = si
counter = counter + 1
else:
tmp_dict["email"] = si
dict.append(tmp_dict)
csv = """Donald,Duck,d.duck#entenhausen.com
Wiley,Coyote,whiley#canyon.org
Road,Runner,roadrunner#canyon.org"""

There is no need for the loop if you already expect name, surname and email.
def string_to_dict(csv):
dict = []
tmp = csv.splitlines()
for i in tmp:
tmp_dict = {"vorname" : "none", "nachname" : "none", "email" : "none"};
tmp_i= i.split(",")
tmp_dict["vorname"] = tmp_i[0]
tmp_dict["nachname"] = tmp_i[1]
tmp_dict["email"] = tmp_i[2]
dict.append(tmp_dict)
We can keep iterating to improve the solution:
def string_to_dict(csv):
dict = []
tmp = csv.splitlines()
for i in tmp:
tmp_dict = {"vorname" : None, "nachname" : None, "email" : None};
tmp_i= i.split(",")
tmp_dict["vorname"] = tmp_i[0]
tmp_dict["nachname"] = tmp_i[1]
tmp_dict["email"] = tmp_i[2]
dict.append(tmp_dict)
And even more (if you want to use a protected keyword like dict, naming convention is to use an underscore after it):
def string_to_dict(csv):
dict_ = []
for line in csv.splitlines():
vor_name, nach_name, email = line.split(",")
dict_.append({"vorname" : vor_name, "nachname" : nach_name, "email" : email})
return dict_
And with list comprehensions:
def string_to_dict(csv):
def _parse_item(vor_name, nach_name, email):
return {"vorname" : vor_name, "nachname" : nach_name, "email" : email}
return [_parse_item(*line.split(",")) for line in csv.splitlines()]

If you want minimal changes to what you have done so far, you can just get list of keys and use the index value (counter variable in your case), something like this:
for i in tmp:
tmp_dict = {"vorname" : "none", "nachname" : "none", "email" : "none"};
tmp_i= i.split(",")
counter = 0;
keys = [*temp_dict.keys()] # List of Keys
for si in tmp_i:
tmp_dict[keys[counter]] = si # Key at index counter
counter += 1
dict.append(tmp_dict)
Sample Run:
>>string_to_dict(csv)
[{'vorname': ' Road', 'nachname': 'Runner', 'email': 'roadrunner#canyon.org'}, {'vorname': ' Road', 'nachname': 'Runner', 'email': 'roadrunner#canyon.org'}, {'vorname': ' Road', 'nachname': 'Runner', 'email': 'roadrunner#canyon.org'}]
Another Note: You're naming the variable as dict You should avoid that since it's a keyword in Python

Lets start with the fact that you are not trying to iterate over a dictionary but to create a list containing dictionary entries from a CSV format string.
secondly there are a lot of python syntactic mistakes and errors in your code.
Refrain from using reserved word such as "dict" as parameter names.
You can use this code snippet as a start if it helps you but I recommend brushing up on python syntax and best practices.
result = []
for line in csv.splitlines():
vorname, nachname, email = line.split(",")
result.append(
{"vorname": vorname.strip(), "nachname": nachname.strip(), "email": email.strip()})
This can be done also using list comprehension, but is much less readable

Related

Passing multiple values from dictionary into method using loop

i have a question regarding adding dictionary key and value to method using loop
This is what i was thinking to write but it doesn't work how i want because it creates a packet just with one key/value every time
for key in packetData:
for name in packetData[key]:
packets = Ether()/IP()/UDP()/createsPacket(key, name=packetData[key][name])
print ("as name " + name + " \n as value " + str(packetData[key][name]))
Instead of writing this manually like that :
packets1 = Ether()/IP()/UDP()/createsPacket("65", UserID = "name", Password = "pass123", ETX = 123)
packets2 = Ether()/IP()/UDP()/createsPacket("72", PriceID = 123, Side = 12, MaxAmount = 123, MinAmount = 123, Price = 123000)
    json then converted to dictionary in python , this is data that i want to pass in
{
"65":{
"UserID":"vcjazfan",
"Password":"ejujwlhk",
"SessionID":115,
"ETX":192
},
"66":{
"UserID":"dzmtrssy",
"SessionID":35,
"Reason":"zbwivjcv",
"ETX":43
},
"72":{
"InstrumentIndex":171,
"PriceID":217,
"Side":226,
"MaxAmount":210,
"MinAmount":219,
"Price":47,
"PriceProvider":207,
"ETX":78
},
Made more generic for easier understanding, hoping it helps
Generic code
dictionary = {"65":{ "UserID":"vcjazfan", "Password":"ejujwlhk", "ETX":192} , "72":{ "InstrumentIndex":171, "PriceID":217, } }
#This is what i was thinking to write but it doesn't work how i want because it creates a packet just with one key/value every time
for key in dictionary:
for name in dictionary[key]:
value=dictionary[key][name]
packets = method(key, name=value) # in first iteration when key is 65 , name = "UserID" , value = "vcjazfan"
# in second iteration when key is 65 , name = "Password" , value = "ejujwlhk"
#Instead of writing this manually like that :
packets1 = method("65", UserID = "name", Password = "pass123", ETX = 123)
packets2 = method("72", InstrumentIndex = 123, PriceID = 12,)
This question solved my problem : How to pass dictionary items as function arguments in python?
solution to my original code:
Allpackets= []
for key in packetData:
Allpackets.append(packets/createsPacket(key, **packetData[key]))
Solution to generic one:
dictionary = {"65":{ "UserID":"vcjazfan", "Password":"ejujwlhk", "ETX":192} , "72":{ "InstrumentIndex":171, "PriceID":217, } }
Allpackets = []
for key in dictionary:
Allpackets.append( method(key, **dictionary))
#Instead of writing this manually like that :
packets1 = method("65", UserID = "name", Password = "pass123", ETX = 123)
packets2 = method("72", InstrumentIndex = 123, PriceID = 12,)

How can I prefix a value in a python dictionary used for an Ansible dynamic inventory?

I'm working on a custom Ansible dynamic inventory python script. I have created groups from k=v pairs, but for certain groups, I want the key prefixed to the values, otherwise the group names are meaningless (1,2,3, etc.)
I've tried sticking the key name in various places, but without a proper understanding of what I'm doing. In the example below, I am trying to get the "bucket" group to have every value look something like bucket_3 (which would then be the Ansible group name).
result = {
'all': {
'hosts': [],
'vars': {},
},
'_meta': {
'hostvars': {}
}
}
server = ''
for raw_line in output.split('\n'):
line = raw_line.strip()
if len(line) > 0 and not line.startswith(comment_char):
if line.endswith(server_char):
server = line[:-1]
result['all']['hosts'].append(server)
result['_meta']['hostvars'][server] = {}
else:
raw_key, raw_value = line.split('=', 1)
key = raw_key.strip()
value = raw_value.strip()
result['_meta']['hostvars'][server][key] = value
if key == 'ansible_groups':
for group in value.split(","):
if group not in result.keys():
result[group] = {'hosts': [], 'vars': {}}
result[group]['hosts'].append(server)
if key == 'bucket':
for group in value:
if group not in result.keys():
result[group] = 'bucket_' + {'hosts': [], 'vars': {}}
result[group]['hosts'].append(server)
I expect to get groups such as bucket_1, bucket_2, etc. (The source has 'bucket = 1', 'bucket = 2', etc.).
Getting error "'bucket_' + {'hosts': [], 'vars': {}} TypeError: cannot concatenate 'str' and
'dict' objects"
granted, this is just my latest attempt, so errors have been varied as I try to find the correct way to modify the group name.
nevermind...just not thinking.
if key == 'bucket':
for group in value:
group = 'bucket_' + group
if group not in result.keys():
still a bit slower than I would like, but it is functional

Python return value without inverted commas

I have csv file:
shack_imei.csv:
shack, imei
F10, "5555"
code:
reader = csv.reader(open("shack_imei.csv", "rb"))
my_dict = dict(reader)
shack = raw_input('Enter Shack:')
print shack
def get_imei_from_entered_shack(shack):
for key, value in my_dict.iteritems():
if key == shack:
return value
list = str(get_imei_from_entered_shack(shack))
print list
which gives me "5555"
But I need this value in a list structure like this:
["5555"]
I've tried a lot of different methods, and they all end up with extra ' or""
EDIT 1:
new simpler code:
reader = csv.reader(open("shack_imei.csv", "rb"))
my_dict = dict(reader)
shack = raw_input('Enter Shack:')
imei = my_dict[shack]
print imei
"5555"
list(imei) gives me ['"5555"'], I need it to be ["5555"]
You can change your "return" sentence:
shack = raw_input('Enter Shack:')
print shack
def get_imei_from_entered_shack(shack):
for key, value in my_dict.iteritems():
if key == shack:
return [str(value)]
list = get_imei_from_entered_shack(shack)
print list
As far as I understand, you want to create a list containing the returned string, which you do with [ ]
list = [str(get_imei_from_entered_shack(shack))]
There are a few problems with this code, which are too long to tackle in comments
my_dict
my_dict = dict(reader) works only well if this csv is a collection of keys and values. If there are duplicate keys, this might give some problems
get_imei_from_entered_shack
Why this special method, instead of just asking my_dict the correct value. Even if you don't want it to trow an Exception when you ask for a shack that doesn't exists, you can use the dict.get(<key>, <default>) method
my_dict(shack, None)
does the same as your 4-line method
list
don't name variables the same as builtins
list2
if you want a list, you can do [<value>] or list(<value>) (unless you replaced list with your own variable assignment)
reader = csv.reader(open("shack_imei.csv", "rb"))
my_dict = dict(reader)
shack = raw_input('Enter Shack:')
imei = my_dict[shack]
imei = imei.replace('"',"")
IMEI_LIST =[]
IMEI_LIST.append(imei)
print IMEI_LIST
['5555']

Python container troubles

Basically what I am trying to do is generate a json list of SSH keys (public and private) on a server using Python. I am using nested dictionaries and while it does work to an extent, the issue lies with it displaying every other user's keys; I need it to list only the keys that belong to the user for each user.
Below is my code:
def ssh_key_info(key_files):
for f in key_files:
c_time = os.path.getctime(f) # gets the creation time of file (f)
username_list = f.split('/') # splits on the / character
user = username_list[2] # assigns the 2nd field frome the above spilt to the user variable
key_length_cmd = check_output(['ssh-keygen','-l','-f', f]) # Run the ssh-keygen command on the file (f)
attr_dict = {}
attr_dict['Date Created'] = str(datetime.datetime.fromtimestamp(c_time)) # converts file create time to string
attr_dict['Key_Length]'] = key_length_cmd[0:5] # assigns the first 5 characters of the key_length_cmd variable
ssh_user_key_dict[f] = attr_dict
user_dict['SSH_Keys'] = ssh_user_key_dict
main_dict[user] = user_dict
A list containing the absolute path of the keys (/home/user/.ssh/id_rsa for example) is passed to the function. Below is an example of what I receive:
{
"user1": {
"SSH_Keys": {
"/home/user1/.ssh/id_rsa": {
"Date Created": "2017-03-09 01:03:20.995862",
"Key_Length]": "2048 "
},
"/home/user2/.ssh/id_rsa": {
"Date Created": "2017-03-09 01:03:21.457867",
"Key_Length]": "2048 "
},
"/home/user2/.ssh/id_rsa.pub": {
"Date Created": "2017-03-09 01:03:21.423867",
"Key_Length]": "2048 "
},
"/home/user1/.ssh/id_rsa.pub": {
"Date Created": "2017-03-09 01:03:20.956862",
"Key_Length]": "2048 "
}
}
},
As can be seen, user2's key files are included in user1's output. I may be going about this completely wrong, so any pointers are welcomed.
Thanks for the replies, I read up on nested dictionaries and found that the best answer on this post, helped me solve the issue: What is the best way to implement nested dictionaries?
Instead of all the dictionaries, I simplfied the code and just have one dictionary now. This is the working code:
class Vividict(dict):
def __missing__(self, key): # Sets and return a new instance
value = self[key] = type(self)() # retain local pointer to value
return value # faster to return than dict lookup
main_dict = Vividict()
def ssh_key_info(key_files):
for f in key_files:
c_time = os.path.getctime(f)
username_list = f.split('/')
user = username_list[2]
key_bit_cmd = check_output(['ssh-keygen','-l','-f', f])
date_created = str(datetime.datetime.fromtimestamp(c_time))
key_type = key_bit_cmd[-5:-2]
key_bits = key_bit_cmd[0:5]
main_dict[user]['SSH Keys'][f]['Date Created'] = date_created
main_dict[user]['SSH Keys'][f]['Key Type'] = key_type
main_dict[user]['SSH Keys'][f]['Bits'] = key_bits

python - Looking up a dictionary key in another file with two criteria

After the end of my code, I have a dictionary like so:
{'"WS1"': 1475.9778073075058, '"BRO"': 1554.1437268304624, '"CHA"': 1552.228925324831}
What I want to do is to find each of the keys in a separate file, teams.txt, which is formatted like this:
1901,'BRO','LAD'
1901,'CHA','CHW'
1901,'WS1','MIN'
Using the year, which is 1901, and the team, which is the key of each item in the dictionary, I want to create a new dictionary where the key is the third column in teams.txt if the year and team both match, and the value is the value of the team in the first dictionary.
I figured this would be easiest if I created a function to "lookup" the year and the team, and return "franch", and then apply that function to each key in the dictionary. This is what I have so far, but it gives me a KeyError
def franch(year, team_str):
team_str = str(team_str)
with open('teams.txt') as imp_file:
teams = imp_file.readlines()
for team in teams:
(yearID, teamID, franchID) = team.split(',')
yearID = int(yearID)
if yearID == year:
if teamID == team_str:
break
franchID = franchID[1:4]
return franchID
And in the other function with the dictionary that I want to apply this function to:
franch_teams={}
for team in teams:
team = team.replace('"', "'")
franch_teams[franch(year, team)] = teams[team]
The ideal output of what I am trying to accomplish would look like:
{'"MIN"': 1475.9778073075058, '"LAD"': 1554.1437268304624, '"CHW"': 1552.228925324831}
Thanks!
Does this code suite your needs?
I am doing an extra check for equality, because there were different string signs in different parts of your code.
def almost_equals(one, two):
one = one.replace('"', '').replace("'", "")
two = two.replace('"', '').replace("'", "")
return one == two
def create_data(year, data, text_content):
""" This function returns new dictionary. """
content = [line.split(',') for line in text_content.split('\n')]
res = {}
for key in data.keys():
for one_list in content:
if year == one_list[0] and almost_equals(key, one_list[1]):
res[one_list[2]] = data[key]
return res
teams_txt = """1901,'BRO','LAD'
1901,'CHA','CHW'
1901,'WS1','MIN'"""
year = '1901'
data = { '"WS1"': 1475.9778073075058, '"BRO"': 1554.1437268304624, '"CHA"': 1552.228925324831 }
result = create_data(year, data, teams_txt)
And the output:
{"'CHW'": 1552.228925324831, "'LAD'": 1554.1437268304624, "'MIN'": 1475.9778073075058}
Update:
To read from text file use this function:
def read_text_file(filename):
with open(filename) as file_object:
result = file_object.read()
return result
teams_txt = read_text_file('teams.txt')
You may try something like:
#!/usr/bin/env python
def clean(_str):
return _str.strip('"').strip("'")
first = {'"WS1"': 1475.9778073075058, '"BRO"': 1554.1437268304624, '"CHA"': 1552.228925324831}
clean_first = dict()
second = dict()
for k,v in first.items():
clean_first[clean(k)] = v
with open("teams.txt", "r") as _file:
lines = _file.readlines()
for line in lines:
_,old,new = line.split(",")
second[new.strip()] = clean_first[clean(old)]
print second
Which gives the expected:
{"'CHW'": 1552.228925324831, "'LAD'": 1554.1437268304624, "'MIN'": 1475.9778073075058}

Categories