I am wondering how I can print all keys in a dictionary on one line and values on the next so they line up.
The task is to create a solitaire card game in python. Made most of it already but I wish to improve on the visual. I know how to use a for loop to print lines for each value and key, but the task I'm doing in school asks me to do it this way. I also just tried to create new lists for each line and "print(list1)" print(list2) but that just looks ugly.
FireKort ={
'A': None,#in my code i have the cards as objects here with value
#and type
'B': None,#ex. object1: 8, cloves; object2: King, hearts
'C': None,
'D': None,
'E': None,
'F': None,
'G': None,
'H': None
}
def f_printK():
global FireKort
for key in FireKort:
print('Stokk:',key,' Gjenstående:',len(FireKort[key]))
try:
print(FireKort[key][0].sort, FireKort[key][0].valør)
except:
print('tom')
##here are the lists i tried:
## navn=[]
## kort=[]
## antall=[]
## for key in FireKort:
## navn.append((key+' '))
## kort.append([FireKort[key][0].sort,FireKort[key][0].valør])
## antall.append( str(len(FireKort[key])))
## print(navn)
## print(kort)
## print(antall)
A B C D E F G H
[♦9][♣A][♠Q][♣8][♦8][♣J][♣10][♦7]
4 4 4 4 4 4 4 4
Have you try to use pprint?
The pprint module provides a capability to “pretty-print arbitrary Python data structures
https://docs.python.org/2/library/pprint.html
Try this:
d = { ... }
keys = [ str(q) for q in d.keys() ]
values = [ str(q) for q in d.values() ]
txts = [ (str(a), str(b)) for a, b in zip(keys, values) ]
sizes = [ max(len(a), len(b)) for a, b in txts ]
formats = [ '%%%ds' % q for q in sizes ]
print(' '.join(a % b for a, b in zip (formats, keys)))
print(' '.join(a % b for a, b in zip (formats, values)))
In short:
first we get str values of keys and values of dictionary d (since we're going to use them twice, we might as well store them locally)
we calculate max size of each "column"
we create formats for % operator
and we print
It could be done using ljust method of str.
Example:
d = {'A':'some','B':'words','C':'of','D':'different','E':'length'}
keys = list(d.keys())
values = list(d.values())
longest = max([len(i) for i in keys]+[len(i) for i in values])
print(*[i.ljust(longest) for i in keys])
print(*[i.ljust(longest) for i in values])
Output:
A B C D E
some words of different length
Note that I harnessed fact that .keys() and .values() return key and values in same order, if no action was undertaken between them regarding given dict.
Related
I was making a program where first parameter is a list and second parameter is a list of dictionaries. I want to return a list of lists like this:
As an example, if this were a function call:
make_lists(['Example'],
[{'Example': 'Made-up', 'Extra Keys' : 'Possible'}]
)
the expected return value would be:
[ ['Made-up'] ]
As an second example, if this were a function call:
make_lists(['Hint', 'Num'],
[{'Hint': 'Length 2 Not Required', 'Num' : 8675309},
{'Num': 1, 'Hint' : 'Use 1st param order'}]
)
the expected return value would be:
[ ['Length 2 Not Required', 8675309],
['Use 1st param order', 1]
]
I have written a code for this but my code does not return a list of lists, it just returns a single list. Please can someone explain?
def make_lists(s,lod):
a = []
lol =[]
i = 0
for x in lod:
for y in x:
for k in s:
if(y==k):
lol.append(x.get(y))
i = i+1
return lol
Expected Output:
[ ['Length 2 Not Required', 8675309],['Use 1st param order', 1] ]
Output:
['Length 2 Not Required', 8675309, 1, 'Use 1st param order']
The whole point of dictionaries, is that you can access them by key:
def make_lists(keys, dicts):
result = []
for d in dicts:
vals = [d[k] for k in keys if k in d]
if len(vals) > 0:
result.append(vals)
return result
Let's have a look what happens here:
We still have the result array, which accumulates the answers, but now it's called result instead of lol
Next we iterate through every dictionary:
for d in dicts:
For each dictionary d, we create a list, which is a lookup in that dictionary for the keys in keys, if the key k is in the dictionary d:
vals = [d[k] for k in keys if k in d]
The specs don't detail this, but I assume if none of the keys are in the dictionary, you don't want it added to the array. For that, we have a check if vals have any results, and only then we add it to the results:
if len(vals) > 0:
result.append(vals)
Try this code - I've managed to modify your existing code slighty, and added explanation in the comments. Essentially, you just need to use a sub-list and add that to the master list lol, and then in each loop iteration over elements in lod, append to the sub-list instead of the outermost list.
def make_lists(s,lod):
a = []
lol =[]
i = 0
for x in lod:
## Added
# Here we want to create a new list, and add it as a sub-list
# within 'lol'
lols = []
lol.append(lols)
## Done
for y in x:
for k in s:
if(y==k):
# Changed 'lol' to 'lols' here
lols.append(x.get(y))
i = i+1
return lol
print(make_lists(['Example'], [{'Example': 'Made-up', 'Extra Keys' : 'Possible'}]))
print(make_lists(['Hint', 'Num'], [{'Hint': 'Length 2 Not Required', 'Num' : 8675309}, {'Num': 1, 'Hint' : 'Use 1st param order'}]))
Prints:
[['Made-up']]
[['Length 2 Not Required', 8675309], [1, 'Use 1st param order']]
A simpler solution
For a cleaner (and potentially more efficient approach), I'd suggest using builtins like map and using a list comprehension to tackle this problem:
def make_lists(s, lod):
return [[*map(dict_obj.get, s)] for dict_obj in lod]
But note, that this approach includes elements as None in cases where the desired keys in s are not present in the dictionary objects within the list lod.
To work around that, you can pass the result of map to the filter builtin function so that None values (which represent missing keys in dictionaries) are then stripped out in the result:
def make_lists(s, lod):
return [[*filter(None, map(dict_obj.get, s))] for dict_obj in lod]
print(make_lists(['Example'], [{'Extra Keys' : 'Possible'}]))
print(make_lists(['Hint', 'Num'], [{'Num' : 8675309}, {'Num': 1, 'Hint' : 'Use 1st param order'}]))
Output:
[[]]
[[8675309], ['Use 1st param order', 1]]
I have a dictionary where each key is a tuple ength N. In each position there is either a string or an empty string.
d = {('Word A','Word B','','','Word C',....) : 50,
('Word F', '','','',....,'Word H') : 10,
....
}
I have a category dictionary containing indexes, if a key in d has an empty string at every position specified by the indexes, it belongs to the category. A key can belong to multiple categories.
category_dictionary= { 'Category A':[1,2,3] , 'Category B' : [0,3,4] , .... }
In this example, the second entry in d ('Word F', '','','',....,'Word H') belongs to Category A since it has an empty string in position 1,2 and 3.
I want to remove all keys in d which do not belong to any category. What would be an efficient way of doing this? Here is code which is working but is slow.
filtered_list = []
for current_tuple in list(d.keys()):
keep_tuple = False
for category,idxs in category_dictionary.items():
all_idxs_empty = True
for idx in idxs:
if current_tuple[idx] != '':
all_idxs_empty = False
if all_idxs_empty:
filtered_list.append(current_tuple)
break
d_filter = {k:v for k,v in d.items() if k in filtered_list}
What would be a more efficient way of doing this? If I have M keys, T categories and the maximum length is U, the complexity is between complexity [O(M*T),O(M*T*U)]
Is there a way to reduce the complexity somehow?
Example data with N = 3 and 2 categories
d = {('A','','B','H') : 10,
('','','','H') : 20,
('','','F','T') : 30,
('A','C','G','') : 0
}
category_dictionary = { 'Category A':[0,1],'Category B' :[3]}
Expected output
d_filter = {('','','','H'): 20,
('','','F','T'):30,
('A','C','G','') : 0
}
Try this:
def f(tuple_, category_dictionary):
l=[i for i in range(len(tuple_)) if tuple_[i]=='']
return any([set(k)-set(l)==set() for k in category_dictionary.values()])
m=list(d.keys())
for i in m:
if not f(i, category_dictionary):
del d[i]
Not sure if this is faster, but this is simpler.
filtered_list = []
category_set = [set(x) for x in category_dictionary.values()]
for current_tuple in list(d.keys()):
#in_category = [i for i,x in enumerate(current_tuple) if x==''] in category_dictionary.values()
current_set = {i for i,x in enumerate(current_tuple) if x==''}
in_category = any([set.issubset(x, current_set) for x in category_set])
if in_category:
filtered_list.append(current_tuple)
d_filter = {k:v for k,v in d.items() if k in filtered_list}
d_filter
I am working on an optimization project where I have a series of dictionaries with tuples as keys and another dictionary (a decision variable with Gurobi) where the key is the first element of the tuples in the other dictionaries. I need to be able to do the following:
data1 = {(place, person): q}
data2 = {person: s}
x = {place: var}
qx = {k: x[k]*data1[k] for k in x}
total1 = {}
for key, value in qx.items():
person = key[1]
if person in total1:
total1[person] = total1[person] + value
else:
total1[person] = value
total2 = {k: total1[k]/data2[k] for k in total1}
(Please note that the data1, data2, and x dictionaries are very large, 10,000+ distinct place/person pairs).
This same process works when I use the raw data in place of the decision variable, which uses the same (place, person) key. Unfortunately, my variable within the Gurobi model itself must be a dictionary and it cannot contain the person key value.
Is there any way to iterate over just the first value in the tuple key?
EDIT:
Here are some sample values (sensitive data, so placeholder values):
data1 = {(1, a): 28, (1, c): 57, (2, b): 125}
data2 = {a: 7.8, b: 8.5, c: 8.4}
x = {1: 0.002, 2: 0.013}
Values in data1 are all integers, data2 are hours, and x are small decimals.
Outputs in total2 should look similar to the following (assuming there are many other rows for each person):
total2 = {a: 0.85, b: 1.2, c: 1.01}
This code is essentially calculating a "productivity score" for each person. The decision variable, x, is looking only at each individual place for business purposes, so it cannot include the person identifiers. Also, the Gurobi package is very limiting about how things can be formatted, so I have not found a way to even use the tuple key for x.
Generally, the most efficient way to aggregate values into bins is to use a for loop and store the values in a dictionary, as you did with total1 in your example. In the code below, I have fixed your qx line so it runs, but I don't know if this matches your intention. I also used total1.setdefault to streamline the code a little:
a, b, c = 'a', 'b', 'c'
data1 = {(1, a): 28, (1, c): 57, (2, b): 125}
data2 = {a: 7.8, b: 8.5, c: 8.4}
x = {1: 0.002, 2: 0.013}
qx = {place, person: x[place] * value for (place, person), value in data1.items()}
total1 = {}
for (place, person), value in qx.items():
total1.setdefault(person, 0.0)
total1[person] += value
total2 = {k: total1[k] / data2[k] for k in total1}
print(total2)
# {'a': 0.0071794871794871795, 'c': 0.013571428571428571, 'b': 0.19117647058823528}
But this doesn't produce the result you asked for. I can't tell at a glance how you get the result you showed, but this may help you move in the right direction.
It might also be easier to read if you moved the qx logic into the loop, like this:
total1 = {}
for (place, person), value in data1.items():
total1.setdefault(person, 0.0)
total1[person] += x[place] * value
total2 = {k: total1[k] / data2[k] for k in total1}
Or, if you want to do this often, it might be worth creating a cross-reference between persons and their matching places, as #martijn-pieters suggested (note, you still need a for loop to do the initial cross-referencing):
# create a list of valid places for each person
places_for_person = {}
for place, person in data1:
places_for_person.setdefault(person, [])
places_for_person[person].append(place)
# now do the calculation
total2 = {
person:
sum(
data1[place, person] * x[place]
for place in places_for_person[person]
) / data2[person]
for person in data2
}
For creating a new dictionary removing the tuple:
a, b, c = "a", "b", "c"
data1 = {(1, a): 28, (1, c): 57, (2, b): 125}
total = list()
spot = 0
for a in data1:
total.append(list(a[1])) # Add new Lists to list "total" containing the Key values
total[spot].append(data1[a]) # Add Values to Keys judging from their spot in the list
spot += 1 # to keep the spot in correct place in lists
total = dict(total) # convert it to dictionary
print(total)
Output:
{'a': 28, 'c': 57, 'b': 125}
If i am doing some math functions for different variables for example:
a = x - y
b = x**2 - y**2
c = (x-y)**2
d = x + y
How can i find the minimum value out of all the variables. For example:
a = 4
b = 7
c = 3
d = 10
So the minimum value is 3 for c. How can i let my program do this.
What have i thought so far:
make a list
append a,b,c,d in the list
sort the list
print list[0] as it will be the smallest value.
The problem is if i append a,b,c,d to a list i have to do something like:
lst.append((a,b,c,d))
This makes the list to be -
[(4,7,3,10)]
making all the values relating to one index only ( lst[0] )
If possible is there any substitute to do this or any way possible as to how can i find the minimum!
LNG - PYTHON
Thank you
You can find the index of the smallest item like this
>>> L = [4,7,3,10]
>>> min(range(len(L)), key=L.__getitem__)
2
Now you know the index, you can get the actual item too. eg: L[2]
Another way which finds the answer in the form(index, item)
>>> min(enumerate(L), key=lambda x:x[1])
(2, 3)
I think you may be going the wrong way to solving your problem, but it's possible to pull values of variable from the local namespace if you know their names. eg.
>>> a = 4
>>> b = 7
>>> c = 3
>>> d = 10
>>> min(enumerate(['a', 'b', 'c', 'd']), key=lambda x, ns=locals(): ns[x[1]])
(2, 'c')
a better way is to use a dict, so you are not filling your working namespace with these "junk" variables
>>> D = {}
>>> D['a'] = 4
>>> D['b'] = 7
>>> D['c'] = 3
>>> D['d'] = 10
>>> min(D, key=D.get)
'c'
>>> min(D.items(), key=lambda x:x[1])
('c', 3)
You can see that when the correct data structure is used, the amount of code required is much less.
If you store the numbers in an list you can use a reduce having a O(n) complexity due the list is not sorted.
numbers = [999, 1111, 222, -1111]
minimum = reduce(lambda mn, candidate: candidate if candidate < mn else mn, numbers[1:], numbers[0])
pack as dictionary, find min value and then find keys that have matching values (possibly more than one minimum)
D = dict(a = 4, b = 7, c = 3, d = 10)
min_val = min(D.values())
for k,v in D.items():
if v == min_val: print(k)
The buiit-in function min will do the trick. In your example, min(a,b,c,d) will yield 3.
For example, if ZZAZAAZ is input, the sum of A would be 14 (since its placement is 3,5,6), while the sum of Z would be 14 (1 + 2 + 4 + 7).
How would I do that?
You can use a generator expression within sum :
>>> s='ZZAZAAZ'
>>> sum(i for i,j in enumerate(s,1) if j=='A')
14
For all the elements in s you could do this. Also, it would find the counts for each element in a single pass of the string s, hence it's linear in the number of elements in s.
>>> s = 'ZZAZAAZ'
>>> d = {}
>>> for i, item in enumerate(s):
... d[item] = d.get(item, 0) + i + 1
>>> print d
{'A': 14, 'Z': 14}
Furthering Kasra's idea of using enumerate, if you wanted a dictionary containing these sums you could use a dictionary comprehension, and iterate over the set of unique characters, like so:
>>> s = 'ZZAZAAZ'
>>> {let:sum(a for a,b in enumerate(s,1) if b==let) for let in set(s)}
{'Z': 14, 'A': 14}