I have a question about change dictionary format.
The dictionary is :
{'index': 'cfs_nucleus_bespoke_88260', 'host': 'iaasn00018224.svr.us.jpmchase.net', 'source': '/logs/tomcat7inst0/localhost_tomcat7inst0_access_log2018-11-02.txt', '_time': '2018-11-02 19:46:50.000 EDT', 'count': '1'}
I want to ask is there a way for me to change the format like below:
{"column1":{'index': 'cfs_nucleus_', 'host': 'iaasn00018224.net'}, "column2":{'source': '/logs/tomcat7inst0/localhost_tomcat7inst0_access_log2018-11-02.txt'}, "column3":{'_time': '2018-11-02, 'count': '1'}}
You can do the following:
dict1 = {'index': 'cfs_nucleus_bespoke_88260', 'host': 'iaasn00018224.svr.us.jpmchase.net', 'source': '/logs/tomcat7inst0/localhost_tomcat7inst0_access_log2018-11-02.txt', '_time': '2018-11-02 19:46:50.000 EDT', 'count': '1'}
d1_items = list(dict1.items())
col_width = 2
dict2 = {f'column{col_num // col_width + 1}': {k: v for k, v in d1_items[col_num:col_num + col_width]} for col_num in range(0, len(dict1), col_width)}
Try it online!
There are a few moving parts that interact to create this solution:
Dict comprehensions
Python has a neat trick where it allows you to embed for in loops in iterable and dict declarations to efficiently cycle and modify a set of elements. Here, the outer iterator is range(0, len(dict1), col_width): this goes through a sequence of integers starting from 0, and progressively increases by col_width until it is greater than or equal to the size of the list, which functions to choose the start index of each col_width-sized dict segment.
Tuple unpacking
dict1.items() is convenient because it returns a dict view of 2-tuples of each dictionary key and its value. Later, we utilize tuple unpacking k: v for k, v in d1_items[ ... ], where a tuple of variables is flattened into two variables that can then easily form a key-value pair of the currrent dictionary comprehension. (This is only in newer versions of Python.)
List slicing
d1_items[col_num:col_num + col_width] is basically a way of getting a sublist. The syntax in relatively straightforward: starting from position col_num, get a sublist up to and excluding the element col_num + col_width (i.e. a sublist of size col_width).
Formatted string literals
Preceding a string with f makes it a formatted string literal. Anything within { } is interpreted as literal Python syntax (with the exception of ', {, and }, which may vary behavior by context.) Here, in f'column{col_num // col_width + 1}', it allows us to label each column with a bit of division and a +1 offset to start counting from 1 instead of 0. (This is new to Python 3.6)
Related
I am having trouble updating a dictionary. i am just extracting certain fields within each key - but the output is not as expected. data, expected output and code are below. Thanks for looking, i appreciate any comments
categories = {'categories_a1' : [{'group': '13GH9', 'number': '1'},{'group': '17KPO', 'number': '73'}, {'group': '26BN11', 'number': '2'}, {'group': '813W', 'number': '99'}],
'categories_a2' : [{'group': '99ITY', 'number': '12'},{'group': 'JH871', 'number': '15'}, {'group': 'OLH83', 'number': '99'}, {'group': '44RTQ', 'number': '1'}]}
xpected= {'categories_a1' : [{'13GH9': '1'},{'17KPO':'73'}, {'26BN11':'2'}, {'813W': '99'}],
'categories_a2' : [{'99ITY':'12'},{'JH871': '15'}, {'OLH83': '99'}, {'44RTQ':'1'}]}
out={}
for k in categories.keys():
for i in categories[k]:
x = {k: v for k, v in zip([i['group']], [i['number']])}
out[k] = x
out.update(out)
Let's first clean up some general weirdness:
out.update(out)
This line does effectively nothing and should be omitted.
x = {k: v for k, v in zip([i['group']], [i['number']])}
This makes little sense; we create lists with one element each and iterate over them in parallel. We could just as easily just use those values directly: x = {i['group']: i['number']}.
After swapping that in, let's consider the part that causes the actual problem:
for i in categories[k]:
x = {i['group']: i['number']}
out[k] = x
The problem here is that you want out[k] to constitute a list of all of the modified dictionaries, but x is repeatedly being assigned one of those dictionaries, and the result then becomes out[k]. What you presumably intended to do is repeatedly append those dictionaries to a new empty list:
x = []
for i in categories[k]:
x.append({i['group']: i['number']})
out[k] = x
However, it's clear that you're already familiar and comfortable with comprehensions, and this is an ideal place to use one:
out[k] = [{i['group']: i['number']} for i in categories[k]]
And, of course, we can extend this technique to the overall loop:
out = {
k: [{i['group']: i['number']} for i in v]
for k, v in categories.items()
}
Please carefully study the structure of this code and make sure you understand the technique. We have a source dictionary that we want to transform to create our output, and the rule is: the key remains unchanged, the value (which is a list) undergoes its own transformation. So we start by writing the skeleton for a dict comprehension, using .items() to give us key-value pairs:
out = {
k: # we need to fill in something to do with `v` here
for k, v in categories.items()
}
Then we figure out what we're doing with the value: each element of the list is a dictionary; the way that we process the list is iterative (each element of the input list tells us an element to use in the output list), but the processing of those elements is not (we look at exactly two hard-coded values from that dict, and make a dict from them). Given an element i of the list, the corresponding dict that we want has exactly one key-value pair, which we can compute as {i['group']: i['number']}. So we wrap a list comprehension around that: [{i['group']: i['number']} for i in v]; and we insert that into the dict comprehension skeleton, giving us the final result.
One approach:
for key, value in categories.items():
categories[key] = [{ d["group"] : d["number"] } for d in value]
print(categories)
Output
{'categories_a1': [{'13GH9': '1'}, {'17KPO': '73'}, {'26BN11': '2'}, {'813W': '99'}], 'categories_a2': [{'99ITY': '12'}, {'JH871': '15'}, {'OLH83': '99'}, {'44RTQ': '1'}]}
I have such following a dict and a list.
mylist= ['1H1.PyModule.md',
'1H2.Class.md',
'1H3.MetaObject.md',
'2B1D0.Data.md',
'2B1D1.Primitive.md',
'2B1D2.Operator.md',
'2B2D3.Container.md',
'2B2S0.Function.md',
'2B2S0.Statemment.md',
'2B2S1.Controlled_Loop.md',
'2B2S2.Conditions.md',
'2B2S3.Except.md',
...
]
mydict = {'Body': {'Data': ['1.primitive', '2.operator', '3.container'],
'Statement': ['0.function', '1.controlled_loop', '2.condition', '3.except']},
'Header': ['1.Modle', '2.Class', '3.Object'],
...}
I attempt to repalce the strings in mydict with the appropriate in mylist
I can figure out '2B1D0.Data.md' has the shortest length,
So I slice the keyward 'Data'
In [82]: '2B1D0.Data.md'[-7:-3]
Out[82]: 'Data'
The dict has both a nested list and nested dict.
So I write a iteration function with type checking
if an item's value isinstance(value,list), renew that value,
if an item's value isinstance(value, dict),call the function replace_ele()to continue.
I name string in mylist as str_of_list,
while string in mydict as str_of_dict for readable concerns.
#replace one string in mydict
def replace_ele(mydict, str_of_list):
for key, value in mydict.items():
if isinstance(value, list): #type checking
for str_of_dict in value:
#replace str_of_dict with str_of_list
if str_of_list[-7:-3].lower() == str_of_dict[-4:]: #[-7:-3] the shortest length
value.remove(str_of_dict)
value.append(str_of_list)
value.sort()
mydict[key] = value
#iteration if a dict
if isinstance(value, dict):
replace_ele(value,str_of_list)
for str_of_list in mylist:
replace_ele(mydict, str_of_list)
Then running and outputs:
Out[117]:
{'Body': {'Data': ['2B1D1.Primitive.md',
'2B1D2.Operator.md',
'2B2D3.Container.md'],
'Statement': ['2B2S0.Function.md',
'2B2S0.Function.md',
'2B2S1.Controlled_Loop.md',
'2B2S3.Except.md']},
'Header': ['1.Modle', '1H2.Class.md', '1H3.MetaObject.md']
....}
I assume that such a problem can be solved with less codes.
However, I cannot find that solution with the limited knowledge.
How to accomplish it elegantly?
My suggestion is that you create a function to reduce element of mylist and elements in lists of mydict values to the same format:
For example, you can split by '.' character, take the second field, convert it to lower case:
def f(s):
return s.split('.')[1].lower()
E.g.:
>>> f('2B2S1.Controlled_Loop.md')
'controlled_loop'
>>> f('1.controlled_loop')
'controlled_loop'
Now, from mylist create a dict to hold replacements:
mylist_repl={f(x): x for x in mylist}
i.e. mylist_repl contains key: value items such as 'metaobject': '1H3.MetaObject.md'.
With dict mylist_repl and function f, it is easy to transform a list from mydict to the desired value, example:
>>> [mylist_repl[f(x)] for x in ['1.primitive', '2.operator', '3.container']]
['2B1D1.Primitive.md', '2B1D2.Operator.md', '2B2D3.Container.md']
Also note that this dictionary lookup is more efficient (i.e.: faster) than a nested for loop!
If you have different replacement logic, you probably only need to change how f maps items from two different sets to a common key.
I have several dictionaries that I would like to merge into a pd.DataFrame. In order to be able to do that, all the dictionaries need to have a dimension of 1. How can I reduce the dimension of the following dictionary to 1 but so that it remains a dictionary? In cases where there are multiple entries for a dictionary item, it should simply be joined. So myFunds should become '2.0 0.0'
h = {
'gameStage': 'PreFlop',
'losses': 0,
'myFunds': [2.0, '0.0'],
'myLastBet': 0,
'peviousRoundCards': ['2S', 'QS'],
'previousCards': ['2S', 'QS'],
'previousPot': 0.03,
'wins': 0
}
To be more precise what my problem is: I want to save all properties of an object in a DataFrame. For that I do vars(Object) which gives me a dictionary, but not all of the entries have the same dimension, so I can't do DataFrame(vars(Object)) because I get an error. That's why I need to first convert vars(Object) into a one dimensional dictionary. But it needs to remain a Dictionary, otherwise I can't convert it into a DataFrame.
You can iterate over the items in the dictionary, and them flatten them with str.join().
We basically tell it to iterate over each key/value pair in the dictionary value, turn it to a string (as you can't concatenate an int and a string), and then put it back in the sictionary
The function func is from here and what it does is makes sure we always have an iterable item
from collections import Iterable
def func(x):
#use str instead of basestring if Python3
if isinstance(x, Iterable) and not isinstance(x, basestring):
return x
return [x]
for key, val in h.items():
h[key] = " ".join([str(ele) for ele in func(val)])
Output of h becomes:
{
'gameStage': 'PreFlop',
'losses': '0',
'myFunds': '2.0 0.0',
'myLastBet': '0',
'peviousRoundCards': '2S QS',
'previousCards': '2S QS',
'previousPot': '0.03',
'wins': '0'
}
I want to copy pairs from this dictionary based on their values so they can be assigned to new variables. From my research it seems easy to do this based on keys, but in my case the values are what I'm tracking.
things = ({'alpha': 1, 'beta': 2, 'cheese': 3, 'delta': 4})
And in made-up language I can assign variables like so -
smaller_things = all values =3 in things
You can use .items() to traverse through the pairs and make changes like this:
smaller_things = {}
for k, v in things.items():
if v == 3:
smaller_things[k] = v
If you want a one liner and only need the keys back, list comprehension will do it:
smaller_things = [k for k, v in things.items() if v == 3]
>>> things = { 'a': 3, 'b': 2, 'c': 3 }
>>> [k for k, v in things.items() if v == 3]
['a', 'c']
you can just reverse the dictionary and pull from that:
keys_values = { 1:"a", 2:"b"}
values_keys = dict(zip(keys_values.values(), keys_values.keys()))
print values_keys
>>> {"a":1, "b":2}
That way you can do whatever you need to with standard dictionary syntax.
The potential drawback is if you have non-unique values in the original dictionary; items in the original with the same value will have the same key in the reversed dictionary, so you can't guarantee which of the original keys would be the new value. And potentially some values are unhashable (such as lists).
Unless you have a compulsive need to be clever, iterating over items is easier:
for key, val in my_dict.items():
if matches_condition(val):
do_something(key)
kindly this answer is as per my understanding of your question .
The dictionary is a kind of hash table , the main intension of dictionary is providing the non integer indexing to the values . The keys in dictionary are just like indexes .
for suppose consider the "array" , the elements in array are addressed by the index , and we have index for the elements not the elements for index . Just like that we have keys(non integer indexes) for values in dictionary .
And there is one implication the values in dictionary are non hashable I mean the values in dictionary are mutable and keys in dictionary are immutable ,simply values could be changed any time .
simply it is not good approach to address any thing by using values in dictionary
This question already has answers here:
How can I convert a dictionary into a list of tuples?
(13 answers)
Closed 3 years ago.
I'm trying to convert a Python dictionary into a Python list, in order to perform some calculations.
#My dictionary
dict = {}
dict['Capital']="London"
dict['Food']="Fish&Chips"
dict['2012']="Olympics"
#lists
temp = []
dictList = []
#My attempt:
for key, value in dict.iteritems():
aKey = key
aValue = value
temp.append(aKey)
temp.append(aValue)
dictList.append(temp)
aKey = ""
aValue = ""
That's my attempt at it... but I can't work out what's wrong?
dict.items()
Does the trick.
Converting from dict to list is made easy in Python. Three examples:
>> d = {'a': 'Arthur', 'b': 'Belling'}
>> d.items()
[('a', 'Arthur'), ('b', 'Belling')]
>> d.keys()
['a', 'b']
>> d.values()
['Arthur', 'Belling']
Your problem is that you have key and value in quotes making them strings, i.e. you're setting aKey to contain the string "key" and not the value of the variable key. Also, you're not clearing out the temp list, so you're adding to it each time, instead of just having two items in it.
To fix your code, try something like:
for key, value in dict.iteritems():
temp = [key,value]
dictlist.append(temp)
You don't need to copy the loop variables key and value into another variable before using them so I dropped them out. Similarly, you don't need to use append to build up a list, you can just specify it between square brackets as shown above. And we could have done dictlist.append([key,value]) if we wanted to be as brief as possible.
Or just use dict.items() as has been suggested.
You should use dict.items().
Here is a one liner solution for your problem:
[(k,v) for k,v in dict.items()]
and result:
[('Food', 'Fish&Chips'), ('2012', 'Olympics'), ('Capital', 'London')]
or you can do
l=[]
[l.extend([k,v]) for k,v in dict.items()]
for:
['Food', 'Fish&Chips', '2012', 'Olympics', 'Capital', 'London']
>>> a = {'foo': 'bar', 'baz': 'quux', 'hello': 'world'}
>>> list(reduce(lambda x, y: x + y, a.items()))
['foo', 'bar', 'baz', 'quux', 'hello', 'world']
To explain: a.items() returns a list of tuples. Adding two tuples together makes one tuple containing all elements. Thus the reduction creates one tuple containing all keys and values and then the list(...) makes a list from that.
Probably you just want this:
dictList = dict.items()
Your approach has two problems. For one you use key and value in quotes, which are strings with the letters "key" and "value", not related to the variables of that names. Also you keep adding elements to the "temporary" list and never get rid of old elements that are already in it from previous iterations. Make sure you have a new and empty temp list in each iteration and use the key and value variables:
for key, value in dict.iteritems():
temp = []
aKey = key
aValue = value
temp.append(aKey)
temp.append(aValue)
dictList.append(temp)
Also note that this could be written shorter without the temporary variables (and in Python 3 with items() instead of iteritems()):
for key, value in dict.items():
dictList.append([key, value])
If you're making a dictionary only to make a list of tuples, as creating dicts like you are may be a pain, you might look into using zip()
Its especialy useful if you've got one heading, and multiple rows. For instance if I assume that you want Olympics stats for countries:
headers = ['Capital', 'Food', 'Year']
countries = [
['London', 'Fish & Chips', '2012'],
['Beijing', 'Noodles', '2008'],
]
for olympics in countries:
print zip(headers, olympics)
gives
[('Capital', 'London'), ('Food', 'Fish & Chips'), ('Year', '2012')]
[('Capital', 'Beijing'), ('Food', 'Noodles'), ('Year', '2008')]
Don't know if thats the end goal, and my be off topic, but it could be something to keep in mind.