How to print many variables' names and their values - python-3.x

I have a big chunk of json code. I assign the needed me values to more than +10 variables. Now I want to print all variable_name = value using print how I can accomplish this task
Expected output is followed
variable_name_1 = car
variable_name_2 = house
variable_name_3 = dog
Updated my code example
leagues = open("../forecast/endpoints/leagues.txt", "r")
leagues_json = json.load(leagues)
data_json = leagues_json["api"["leagues"]
for item in data_json:
league_id = item["league_id"]
league_name = item["name"]
coverage_standings = item["coverage"]["standings"]
coverage_fixtures_events =
item["coverage"]["fixtures"]["events"]
coverage_fixtures_lineups =
item["coverage"]["fixtures"]["lineups"]
coverage_fixtures_statistics =
item["coverage"]["fixtures"]["statistics"]
coverage_fixtures_players_statistics = item["coverage"]["fixtures"]["players_statistics"]
coverage_players = item["coverage"]["players"]
coverage_topScorers = item["coverage"]["topScorers"]
coverage_predictions = item["coverage"]["predictions"]
coverage_odds = item["coverage"]["odds"]
print("leagueName:" league_name,
"coverageStandings:" coverage_standings,
"coverage_fixtures_events:"
coverage_fixtures_events,
"coverage_fixtures_lineups:"
coverage_fixtures_lineups,
"coverage_fixtures_statistics:"
coverage_fixtures_statistics,
"covage_fixtes_player_statistics:"
covage_fixres_players_statistics,
"coverage_players:"
coverage_players,
"coverage_topScorers:"
coverage_topScorers,
"coverage_predictions:"
coverage_predictions,
"coverage_odds:"coverage_odds)

Since you have the JSON data loaded as Python objects, you should be able to use regular loops to deal with at least some of this.
It looks like you're adding underscores to indicate nesting levels in the JSON object, so that's what I'll do here:
leagues = open("../forecast/endpoints/leagues.txt", "r")
leagues_json = json.load(leagues)
data_json = leagues_json["api"]["leagues"]
def print_nested_dict(data, *, sep='.', context=''):
"""Print a dict, prefixing all values with their keys,
and joining nested keys with 'separator'.
"""
for key, value in data.items():
if context:
key = context + sep + key
if isinstance(value, dict):
print_nested_dict(value, sep=sep, context=key)
else:
print(key, ': ', value, sep='')
print_nested_dict(data_json, sep='_')
If there is other data in data_json that you do not want to print, the easiest solution might be to add a variable listing the names you want, then add a condition to the loop so it only prints those names.
def print_nested_dict(data, *, separator='.', context=None, only_print_keys=None):
...
for key, value in data.items():
if only_print_keys is not None and key not in only_print_keys:
continue # skip ignored elements
...
That should work fine unless there is a very large amount of data you're not printing.
If you really need to store the values in variables for some other reason, you could assign to global variables if you don't mind polluting the global namespace.
def print_nested_dict(...):
...
else:
name = separator.join(contet)
print(name, ': ', value, sep='')
globals()[name] = value
...

Related

Python3 f string vs .replace [duplicate]

This question already has answers here:
advanced string formatting vs template strings
(6 answers)
Closed 2 years ago.
I have a text file where most of the text is boilerplate, with around two dozen variables that I'm changing in Python depending on the room that the file pertains to. Which method of replacing the text is "better", wrapping the entire text file into one big triple quoted f'string', or stacking up a bunch of .replace() ?
The file isn't very big and there's only about 300 rooms, so in my case milliseconds don't really matter. I'm thinking that for readability and future edits the .replace() way would be better, but I don't want to create a bad habit if doing it that way is a bad idea. Thanks in advance for any help.
simplified pseudo code:
class Thing:
def __init__(self, name, var1, var2, var3):
self.name = name
self.var1 = var1
self.var2 = var2
self.var3 = var3
def doing_it_the_replace_way(thing):
with open('template.txt', 'r') as file:
file_data = file.read()
file_data = file_data.replace('placeholder_name', 'name')
file_data = file_data.replace('placeholder1', 'var1')
file_data = file_data.replace('placeholder2', 'var2')
file_data = file_data.replace('placeholder3', 'var3') # etc.
with open('output file.txt', 'w') as file:
file.write(file_data)
def doing_it_the_f_string_way(thing):
file_data = f"""This is the entire template text from {thing.var1} about the time I got a
{thing.var2} stuck in my {thing.var3} at band camp."""
with open('output file.txt', 'w') as file:
file.write(file_data)
I'd use neither.
Using regex will be safer (ie you don't need to f-string and eval the entire file) and scalable (you don't need 30 calls to str.replace if you have 30 variables, just an entry in the mapping dict).
import re
table = {'<time>': '12:00',
'<date>': '1.1.1970'}
# imagine this being read from a file
string = '<time>, fixed text, <date>'
print(re.sub(r'(<.+?>)', lambda s: table.get(s.group(1), s.group(1)), string))
outputs
12:00, fixed text, 1.1.1970
Adapting to your case (where the values are attributes of an object)
All you have to do is use the object as the values for mapping dict.
...
thing = Thing('name', 'a', 'b', 'c')
table = {'<time>': thing.var1,
'<date>': thing.var2}
...
This can become cumbersome if you need to do something more complex (like if you have multiple objects) but of course it can be improved depending on your exact use-case.
For example, if the name of the placeholders coincide with the name of the attributes in the object you can just use vars as the mapping (don't forget to remove the < and > from the regex capturing group):
import re
class Thing:
def __init__(self, name, var1, var2, var3):
self.name = name
self.var1 = var1
self.var2 = var2
self.var3 = var3
thing = Thing('name', 'a', 'b', 'c')
string = '<var1>, fixed text, <var2>'
print(re.sub(r'<(.+?)>', lambda s: vars(thing).get(s.group(1), s.group(1)), string))
outputs
a, fixed text, b

how to add key and value in dictionary python?

I am trying to add some value and key in python dictionary using following script
print('phone book contacts')
contacts = input('how many contacts to add: ')
i = 0
for i in range(int(contacts)):
phone_book = {}
a = input('name: ')
b = input('number: ')
phone_book[a] = b
print(phone_book)
when i input 2 key & value like these:
adam : 08123
daniel : 0877
I expect the output will be like these:
{'adam':'08123', 'daniel':'0877'}
instead I get the following output:
{'daniel': '1234'}
any ideas how to show dictionary key & value similar with my expected output?
You can try something like this:
class my_dictionary(dict):
# __init__ function
def __init__(self):
self = dict()
# Function to add key:value
def add(self, key, value):
self[key] = value
# Main Function
dict_obj = my_dictionary()
# Taking input key = 1, value = test
dict_obj.key = input("Enter the key: ")
dict_obj.value = input("Enter the value: ")
dict_obj.add(dict_obj.key, dict_obj.value)
dict_obj.add(2, 'test2')
print(dict_obj)
Use update() method of dictionary class in python.
So if applied to your code
It would be
print('phone book contacts')
contacts = input('how many contacts to add: ')
i = 0
phone_book = {}
for i in range(int(contacts)):
a = input('name: ')
b = int(input('number: '))
phone_book.update({a : b})
print(phone_book)
Since number is integer you have to use curly braces.
And yes move phone_book = {} above the loop because it will be set to empty every time it loops.

Read out .csv and hand results to a dictionary

I am learning some coding, and I am stuck with an error I can't explain. Basically I want to read out a .csv file with birth statistics from the US to figure out the most popular name in the time recorded.
My code looks like this:
# 0:Id, 1: Name, 2: Year, 3: Gender, 4: State, 5: Count
names = {} # initialise dict names
maximum = 0 # store for maximum
l = []
with open("Filepath", "r") as file:
for line in file:
l = line.strip().split(",")
try:
name = l[1]
if name in names:
names[name] = int(names[name]) + int(l(5))
else:
names[name] = int(l(5))
except:
continue
print(names)
max(names)
def max(values):
for i in values:
if names[i] > maximum:
names[i] = maximum
else:
continue
return(maximum)
print(maximum)
It seems like the dictionary does not take any values at all since the print command does not return anything. Where did I go wrong (incidentally, the filepath is correct, it takes a while to get the result since the .csv is quite big. So my assumption is that I somehow made a mistake writing into the dictionary, but I was staring at the code for a while now and I don't see it!)
A few suggestions to improve your code:
names = {} # initialise dict names
maximum = 0 # store for maximum
with open("Filepath", "r") as file:
for line in file:
l = line.strip().split(",")
names[name] = names.get(name, 0) + l[5]
maximum = [(v,k) for k,v in names]
maximum.sort(reversed=True)
print(maximum[0])
You will want to look into Python dictionaries and learn about get. It helps you accomplish the objective of making your names dictionary in less lines of codes (more Pythonic).
Also, you used def to generate a function but you never called that function. That is why it's not printing.
I propose the shorted code above. Ask if you have questions!
Figured it out.
I think there were a few flow issues: I called a function before defining it... is that an issue or is python okay with that?
Also I think I used max as a name for a variable, but there is a built-in function with the same name, that might cause an issue I guess?! Same with value
This is my final code:
names = {} # initialise dict names
l = []
def maxval(val):
maxname = max(val.items(), key=lambda x : x[1])
return maxname
with open("filepath", "r") as file:
for line in file:
l = line.strip().split(",")
name = l[1]
try:
names[name] = names.get(name, 0) + int(l[5])
except:
continue
#print(str(l))
#print(names)
print(maxval(names))

Forming a target string using minimal substrings of words from a word list

I have a text file with first names but there are new names added every year.
I need a program in Python that takes parts of names from the text file and finds some combination of substrings of these names that can be concatenated to create a string that matches a user's input.
The program should do this using the fewest possible available names from the text file.
For example, if the text file contains this:
Joppe
Fien
Katrijn
Sven
Kobe
The program asks for a name that isn't already in the text file. For example:
Please fill in a name: Katrien
Then it should print this:
Katri => Katrijn
ien => Fien
Not like this--it builds the name correctly, but there is a better solution that uses fewer words:
K => Kobe
a => Katrijn
tr => Katrijn
ien => Fien
If the text file contains this:
Joppe
Fien
Makatrijn
Sven
Kobe
It could also print this:
Katr => Makatrijn
ien => Fien
I tried this but with no result:
name_input = input('Fill in a name: ')
with open('namen.txt', 'r') as file:
for name in file.readlines():
for letter_name_input in name_input:
for letter in name:
if letter == letter_name_input:
print(letter)
You can use a function that takes a target name and a set of names as input, tries matching a prefix of the target name with each name in the set of names, from the longest to the shortest, and for each matching name, recursively finds the names that would form the target name with the prefix removed, from the set of names with the matching name removed, and yields each of the returning combinations with the current prefix and name prepended as a tuple:
def form_name(target, names):
if target:
for i in range(len(target), 0, -1):
prefix = target[:i]
matching_names = [name for name in names if prefix.lower() in name.lower()]
if matching_names:
for name in matching_names:
for fragments in form_name(target[i:], names - {name}):
yield [(prefix, name), *fragments]
else:
yield []
so that you can use the min function with len as the key function to obtain the combination with the fewest names:
from io import StringIO
file = StringIO('''Joppe
Fien
Katrijn
Sven
Kobe''')
for fragment, name in min(form_name('Katrien', set(file.read().split())), key=len):
print(fragment, '=>', name)
outputs:
Katri => Katrijn
en => Fien
Demo: https://repl.it/repls/IllustriousTrustingIntegrationtesting
Note that both Fien and Sven in your example input would match the en fragment and make for valid answers with the fewest names, so the min function would arbitrarily return one of them (which is fine per your requirement). Also note that you shouldn't expect the fragments of the target name to overlap, so instead of ien the second fragment should be en after the first fragment Katri is removed from the target name Katrien.
If you're interested in seeing all the valid answers, you can calculate the minimum length of all the combinations first and then output all the combinations with the minimum length:
combinations = list(form_name('Katrien', set(file.read().split())))
min_len = min(map(len, combinations))
for combination in combinations:
if len(combination) == min_len:
for fragment, name in combination:
print(fragment, '=>', name)
print()
This outputs:
Katri => Katrijn
en => Sven
Katri => Katrijn
en => Fien
Katr => Katrijn
ien => Fien
Assuming you'd want to stop searching as soon as you find a shortest answer, here's my solution:
First you need a function to break the word into all possible parts starting from the biggest possible set:
def breakWord(word, n):
list = []
for k in range(len(word)):
subword = word[k:]
out = [(subword[i:i+n]) for i in range(0, len(subword), n)]
if(k > 0):
out.append(word[:k])
list.append(out)
return list
Notice that if you use:
breakWord(yourWord, len(yourWord)-1)
It will break the word into all possible sets of two parts.
Then a function to check if a given string is in the list of names:
def isInNames(word):
for name in name_list:
if(word in name):
return true
return false
Finally iterate over the whole possible combination of characters:
def findWordCombination(word):
resultSet = []
resultSize = 50 #Something large to ensure it gets changed
for i in range(len(word)-1, 0, -1): #Will go from max to minimum
testSet = breakWord(word, i)
for set in testSet:
isValid = true #assumes true at first
for part in set:
if(not isInNames(part)):
isValid = false
#Once all parts of the set are checked we find
#If the set is valid. i.e. it is a valid combination.
if(isValid and len(set) < resultSize):
resultSize = len(set)
resultList = set
return resultList
This will return the first set that finds with the minimum possible combination of subwords from your search query. You can tweak it to have it store the words names from the list that yielded the resulting set.
Yet another approach (I upvoted #blhsing's recursive solution already, very elegant, I love it)
import itertools as it
from collections import defaultdict
def get_all_substrings(input_string):
length = len(input_string)
return [input_string[i:j+1] for i in range(length) for j in range(i,length)]
names = ['Joppe', 'Fien', 'Katrijn', 'Sven', 'Kobe']
d = defaultdict(list) # each key is a substring of any of the names and the value is the list of names that contain it
for name in names:
for subname in get_all_substrings(name):
d[subname].append(name)
input_name = 'Katrien'
input_subs = get_all_substrings(input_name)
sub_combs = [it.combinations(input_subs, n) for n in range(1,len(input_name))]
whole_combs = [el for co in sub_combs for el in co if ''.join(el) == input_name] # those combs that can form the input name
saved = [wc for wc in whole_combs if all((c in d for c in wc))] # those whole combinations that actually appear
shortest_comb = min(saved, key=len)
shortest_sub_and_name = [(s, d[s]) for s in shortest_comb]
for s, ns in shortest_sub_and_name:
print(f"{s} => {ns}")
produces
Katr => ['Katrijn']
ien => ['Fien']
Note: as you can see, the output shows all the names that can contribute to each specific substring
you could try:
import difflib
name = input('Please fill in a name: ')
with open('namen.txt', 'r') as file:
file_data = file.readlines()
# either you are looking for
print([i for i in file_data if difflib.SequenceMatcher(a = i,b = name).ratio() >= 0.5])
#or you are looking for
print(difflib.get_close_matches(name,file_data,len(file_data),0.5))
['Katrijn\n', 'Fien\n']

How to add field name in python in arcgis?

I am making one tool, and for this I want to save result of this tool in field that I've added. I want give name to that field on the basis of amenity selection (Here I've given data type of amenity as string. and added a list of values in amenity parameter like Education, Medical, Transportation, etc.). If I select "education" from amenities then my field name is like "Edu_IC". How can I do this? I've added my code snippet below
def setupVulnerability():
GP = ARC.create(9.3)
print(SYS.version)
InputFC = GP.GetParameterAsText(0) # Input Feature Class
print "InputFC:-'%s'" % (InputFC)
Fields = GP.GetParameterAsText(1)
print "Fields:-'%s'" % (Fields)
fieldList = Fields.split(";")
print "fieldList:-'%s'" % (fieldList)
amenity = GP.GetParameterAsText(2)
print "amen:-'%s'" % (amenity)
all_field_names = [f.name for f in arcpy.ListFields(InputFC)]
field_Name = None
try:
for field in fieldList:
field_Name = field[0:3]+ "_" + "IC"
if field_Name in all_field_names:
continue
else :
GP.AddField(InputFC , field_Name , "FLOAT")
field_Name = None
except:
raise ERROR.ScriptError()
if __name__ == '__main__':
setupVulnerability()
I believe the problem is that your "amenity" variable, which receives input from the user, is not referenced when the field is being added.
Something like this should work:
amenity = GP.GetParameterAsText(2)
if amenity == "Education":
field_name = amenity[:3] + "_IC"
GP.AddField(InputFC, field_Name, "FLOAT")

Resources