Split list elements to key/val dictionary - python

I have this:
query='id=10&q=7&fly=none'
and I want to split it to create a dictionary like this:
d = { 'id':'10', 'q':'7', 'fly':'none'}
How can I do it with little code?

By splitting twice, once on '&' and then on '=' for every element resulting from the first split:
query='id=10&q=7&fly=none'
d = dict(i.split('=') for i in query.split('&'))
Now, d looks like:
{'fly': 'none', 'id': '10', 'q': '7'}

In your case, the more convenient way would be using of urllib.parse module:
import urllib.parse as urlparse
query = 'id=10&q=7&fly=none'
d = {k:v[0] for k,v in urlparse.parse_qs(query).items()}
print(d)
The output:
{'id': '10', 'q': '7', 'fly': 'none'}
Note, that urlparse.parse_qs() function would be more useful if there multiple keys with same value in a query string. Here is an example:
query = 'id=10&q=7&fly=none&q=some_identifier&fly=flying_away'
d = urlparse.parse_qs(query)
print(d)
The output:
{'q': ['7', 'some_identifier'], 'id': ['10'], 'fly': ['none', 'flying_away']}
https://docs.python.org/3/library/urllib.parse.html#urllib.parse.parse_qs

This is what I came up with:
dict_query = {}
query='id=10&q=7&fly=none'
query_list = query.split("&")
for i in query_list:
query_item = i.split("=")
dict_query.update({query_item[0]: query_item[1]})
print(dict_query)
dict_query returns what you want. This code works by splitting the query up into the different parts, and then for each of the new parts, it splits it by the =. It then updates the dict_query with each new value. Hope this helps!

Related

Define a function to generate a dictionary

def create_dictionary(params)
How do I generate a dictionary from a string value which comes
from its parameter named params. The dictionary is created with the use of zip function to handle the keys and values which are generated from params
How do I make the output of this:
print(create_dictionary('name:= Jack ; grade:=3'))
To be like this:
{'name': 'Jack', 'grade': '3'}
def create_dictionary(string1):
s = string1.split(';')
dic = {}
for i in s:
key, value = i.split(':=')
dic[key] = value
return dic
If the string's syntax is same all the time, you can split the string accordingly. In this case:
First split them with ; to separate dictionary values.
Then split rest with := to get the key and the value. You may want to trim the resulting key and value to remove the white spaces around.
Note: If data itself contains the ; or :=, this solution will fail.
Edit
In addition to the Daniel Paul's answer for removing the white spaces:
def create_dictionary(string1):
s = string1.split(';')
dic = {}
for i in s:
key, value = i.split(':=')
dic[key.strip()] = value.strip()
return dic
Before: {'name': ' Jack ', ' grade': '3'} after {'name': 'Jack', 'grade': '3'}
One-liner using python's dict comprehension:
def create_dictionary(string):
{a.strip():b.strip() for a,b in [i.split(':=') for i in string.split(';')]}
You can use the split method and split := or you can follow up my code
def dict_fun(*args):
dict = {}
cnt = 0
count = 0
while cnt < len(args):
for i in args[cnt]:
if i == ':':
print(count)
dict[args[cnt][0:count]] = args[cnt].strip().replace(' ','')[count+2:]
break
else:
count += 1
cnt += 1
count = 0
return(dict)
print(dict_fun('name:=Jack', 'grade:=3'))
OUTPUT
{'name': 'Jack', 'grade': '3'}
Now you can give as many argument as many you want inside dict_fun('name:=jack','grade:=3',etc..) so as of taking single string now you can give mutiple string argument to the function and it would return you the dict of that string..

Express list comprehension as for loop

I'm currently trying to wrap my head around list comprehensions and try to get some practice by taking examples and form loops out of comprehensions and vice versa. Probably a really easy mistake, or a forest for the trees situation. Take the following expression taken from an example project:
rows = []
data = ['a', 'b']
res = ['1', '2']
rows.append({data[counter]: res[counter] for counter, _ in enumerate(data)})
print(rows):
[{'a': '1', 'b': '2'}]
How do i do this as a for loop? The following wraps each loop into a curly bracket instead of both.
for counter, _ in enumerate(data):
rows.append({data[counter]: res[counter]})
print(rows):
[{'a': '1'}, {'b': '2'}]
Am i missing something? Or do i have to merge the items by hand when using a for loop?
The problem in your code is that you create a dictionary for each item in data and append it to rows in each iteration.
In order to achieve the desired behaviour, you should update the same dict in each iteration and after you finish working on your dictionary, only then you should append it to rows.
Try this:
rows = []
data = ['a', 'b']
res = ['1', '2']
payload = {}
for counter, val in enumerate(data):
payload[val] = res[counter]
rows.append(payload)
Another compact way to write it might be:
rows.append(dict(zip(data,res)))
On every iteration of for loop you are creating a new dictionary and appending it into a list if you want to store a whole dictionary in a list then You should try something like that it outputs as you expected:
rows = []
data = ['a', 'b']
res = ['1', '2']
myDict = {}
for counter, _ in enumerate(data):
myDict[data[counter]]= res[counter]
rows.append(myDict)
print(rows)
Output:
[{'b': '2', 'a': '1'}]

Grouping values to a list in dict

While reading a csv file using csv.DictReader
I get
[{'id': 1, 'status1': '1', 'status2': '2', 'status3': '3' }]
How can I manuplate while reading or later to get:
[{'id': 1, 'status': ['1', '2', '3']}]
TLDR;
I want to group similar fields into a list.
and/or - how can i do this in pandas pd.read_csv() too?
Thanks in advance!
If it is certain that the only fields you want to group are those who end with digits, you can use a regex to identify them, and append their corresponding values to a list:
import re
def compact_dict(d):
compact = {}
for key, value in d.items():
# a group containing anything, followed by at least one digit
m = re.match(r'(.*)\d+', key)
if m:
# the key that we use is the original one without the final digits
compact.setdefault(m.group(1), []).append(value)
else:
# not part of a group of similar keys, we just store the key:value pair
compact[key] = value
return compact
data = [{'id': 1, 'status1': '1', 'status2': '2', 'status3': '3' }]
out = [compact_dict(d) for d in data]
print(out)
# [{'id': 1, 'status': ['1', '2', '3']}]

Inverse of string format in python

In python, we can use str.format to construct string like this:
string_format + value_of_keys = formatted_string
Eg:
FMT = '{name:} {age:} {gender}' # string_format
VoK = {'name':'Alice', 'age':10, 'gender':'F'} # value_of_keys
FoS = FMT.format(**VoK) # formatted_string
In this case, formatted_string = 'Alice 10 F'
I just wondering if there is a way to get the value_of_keys from formatted_string and string_format? It should be function Fun with
VoK = Fun('{name:} {age:} {gender}', 'Alice 10 F')
# the value of Vok is expected as {'name':'Alice', 'age':10, 'gender':'F'}
Is there any way to get this function Fun?
ADDED :
I would like to say, the '{name:} {age:} {gender}' and 'Alice 10 F' is just a simplest example. The realistic situation could be more difficult, the space delimiter may not exists.
And mathematically speaking, most of the cases are not reversible, such as:
FMT = '{key1:}{key2:}'
FoS = 'HelloWorld'
The VoK could be any one in below:
{'key1':'Hello','key2':'World'}
{'key1':'Hell','key2':'oWorld'}
....
So to make this question well defined, I would like to add two conditions:
1. There are always delimiters between two keys
2. All delimiters are not included in any value_of_keys.
In this case, this question is solvable (Mathematically speaking) :)
Another example shown with input and expected output:
In '{k1:}+{k2:}={k:3}', '1+1=2' Out {'k1':1,'k2':2, 'k3':3}
In 'Hi, {k1:}, this is {k2:}', 'Hi, Alice, this is Bob' Out {'k1':'Alice', 'k2':'Bob'}
You can indeed do this, but with a slightly different format string, called regular expressions.
Here is how you do it:
import re
# this is how you write your "format"
regex = r"(?P<name>\w+) (?P<age>\d+) (?P<gender>[MF])"
test_str = "Alice 10 F"
groups = re.match(regex, test_str)
Now you can use groups to access all the components of the string:
>>> groups.group('name')
'Alice'
>>> groups.group('age')
'10'
>>> groups.group('gender')
'F'
Regex is a very cool thing. I suggest you learn more about it online.
I wrote a funtion and it seems work:
import re
def Fun(fmt,res):
reg_keys = '{([^{}:]+)[^{}]*}'
reg_fmts = '{[^{}:]+[^{}]*}'
pat_keys = re.compile(reg_keys)
pat_fmts = re.compile(reg_fmts)
keys = pat_keys.findall(fmt)
lmts = pat_fmts.split(fmt)
temp = res
values = []
for lmt in lmts:
if not len(lmt)==0:
value,temp = temp.split(lmt,1)
if len(value)>0:
values.append(value)
if len(temp)>0:
values.append(temp)
return dict(zip(keys,values))
Usage:
eg1:
fmt = '{k1:}+{k2:}={k:3}'
res = '1+1=2'
print Fun(fmt,res)
>>>{'k2': '1', 'k1': '1', 'k': '2'}
eg2:
fmt = '{name:} {age:} {gender}'
res = 'Alice 10 F'
print Fun(fmt,res)
>>>
eg3:
fmt = 'Hi, {k1:}, this is {k2:}'
res = 'Hi, Alice, this is Bob'
print Fun(fmt,res)
>>>{'k2': 'Bob', 'k1': 'Alice'}
There is no way for python to determine how you created the formatted string once you get the new string.
For example: once your format "{something} {otherthing}" with values with space and you get the desired string, you can not differentiate whether the word with space was the part of {something} or {otherthing}
However you may use some hacks if you know about the format of the new string and there is consistency in the result.
For example, in your given example: if you are sure that you'll have word followed by space, then a number, then again a space and then a word, then you may use below regex to extract the values:
>>> import re
>>> my_str = 'Alice 10 F'
>>> re.findall('(\w+)\s(\d+)\s(\w+)', my_str)
[('Alice', '10', 'F')]
In order to get the desired dict from this, you may update the logic as:
>>> my_keys = ['name', 'age', 'gender']
>>> dict(zip(my_keys, re.findall('(\w+)\s(\d+)\s(\w+)', my_str)[0]))
{'gender': 'F', 'age': '10', 'name': 'Alice'}
I suggest another approach to this problem using **kwargs, such as...
def fun(**kwargs):
result = '{'
for key, value in kwargs.iteritems():
result += '{}:{} '.format(key, value)
# stripping the last space
result = result[:-1]
result += '}'
return result
print fun(name='Alice', age='10', gender='F')
# outputs : {gender:F age:10 name:Alice}
NOTE : kwargs is not an ordered dict, and will only keep the parameters order up to version 3.6 of Python. If order is something you with to keep, it is easy though to build a work-around solution.
This code produces strings for all the values, but it does split the string into its constituent components. It depends on the delimiter being a space, and none of the values containing a space. If any of the values contains a space this becomes a much harder problem.
>>> delimiters = ' '
>>> d = {k: v for k,v in zip(('name', 'age', 'gender'), 'Alice 10 F'.split(delimiters))}
>>> d
{'name': 'Alice', 'age': '10', 'gender': 'F'}
for your requirement, I have a solution.
This solution concept is:
change all delimiters to same delimiter
split input string by the same delimiter
get the keys
get the values
zip keys and values as dict
import re
from collections import OrderedDict
def Func(data, delimiters, delimiter):
# change all delimiters to delimiter
for d in delimiters:
data[0] = data[0].replace(d, delimiter)
data[1] = data[1].replace(d, delimiter)
# get keys with '{}'
keys = data[0].split(delimiter)
# if string starts with delimiter remove first empty element
if keys[0] == '':
keys = keys[1:]
# get keys without '{}'
p = re.compile(r'{([\w\d_]+):*.*}')
keys = [p.match(x).group(1) for x in keys]
# get values
vals = data[1].split(delimiter)
# if string starts with delimiter remove first empty element
if vals[0] == '':
vals = vals[1:]
# pack to a dict
result_1 = dict(zip(keys, vals))
# if you need Ordered Dict
result_2 = OrderedDict(zip(keys, vals))
return result_1, result_2
The usage:
In_1 = ['{k1}+{k2:}={k3:}', '1+2=3']
delimiters_1 = ['+', '=']
result = Func(In_1, delimiters_1, delimiters_1[0])
# Out_1 = {'k1':1,'k2':2, 'k3':3}
print(result)
In_2 = ['Hi, {k1:}, this is {k2:}', 'Hi, Alice, this is Bob']
delimiters_2 = ['Hi, ', ', this is ']
result = Func(In_2, delimiters_2, delimiters_2[0])
# Out_2 = {'k1':'Alice', 'k2':'Bob'}
print(result)
The output:
({'k3': '3', 'k2': '2', 'k1': '1'},
OrderedDict([('k1', '1'), ('k2', '2'), ('k3', '3')]))
({'k2': 'Bob', 'k1': 'Alice'},
OrderedDict([('k1', 'Alice'), ('k2', 'Bob')]))
try this :
import re
def fun():
k = 'Alice 10 F'
c = '{name:} {age:} {gender}'
l = re.sub('[:}{]', '', c)
d={}
for i,j in zip(k.split(), l.split()):
d[j]=i
print(d)
you can change the fun parameters as your wish and assign it to variables. It accepts the same string you want to give. and gives the dict like this:
{'name': 'Alice', 'age': '10', 'gender': 'F'}
I think the only right answer is that, what you are searching for isn't really possible generally after all. You just don't have enough information. A good example is:
#python 3
a="12"
b="34"
c="56"
string=f"{a}{b}{c}"
dic = fun("{a}{b}{c}",string)
Now dic might be {"a":"12","b":"34","c":"56"} but it might as well just be {"a":"1","b":"2","c":"3456"}. So any universal reversed format function would ultimately fail to this ambiguity. You could obviously force a delimiter between each variable, but that would defeat the purpose of the function.
I know this was already stated in the comments, but it should also be added as an answer for future visitors.

String to dict conversion

I want to convert string in dictionary and my string is as follow
order_id=BW_225996&tracking_id=306003083135&bank_ref_no=1489730168508&order_status=Success&failure_message=&payment_mode=Net Banking&card_name=AvenuesTest&status_code=null&status_message=Y&currency=INR&amount=100.0&billing_name=test&billing_address=test&billing_city=Pune&billing_state=Maharashtra&billing_zip=411041&billing_country=India&billing_tel=1234567890&billing_email=test#gmail.com&delivery_name=test&delivery_address=test&delivery_city=Pune&delivery_state=Maharashtra&delivery_zip=411041&delivery_country=India&delivery_tel=1234567890&merchant_param1=3&merchant_param2=&merchant_param3=&merchant_param4=&merchant_param5=&vault=N&offer_type=null&offer_code=null&discount_value=0.0&mer_amount=100.0&eci_value=null&retry=N&response_code=0&billing_notes=&trans_date=17/03/2017 11:27:30&bin_country=
You can use split method to split this string:
c="order_id=BW_225996&tracking_id=306003083135"
print {p.split("=")[0]:p.split("=")[1] for p in c.split("&")}
Output:
{'order_id': 'BW_225996', 'tracking_id': '306003083135'}
You can try:
>>> s = """order_id=BW_225996&tracking_id=306003083135&bank_ref_no=1489730168508&order_status=Success&failure_message=&payment_mode=Net Banking&card_name=AvenuesTest&status_code=null&status_message=Y&currency=INR&amount=100.0&billing_name=test&billing_address=test&billing_city=Pune&billing_state=Maharashtra&billing_zip=411041&billing_country=India&billing_tel=1234567890&billing_email=test#gmail.com&delivery_name=test&delivery_address=test&delivery_city=Pune&delivery_state=Maharashtra&delivery_zip=411041&delivery_country=India&delivery_tel=1234567890&merchant_param1=3&merchant_param2=&merchant_param3=&merchant_param4=&merchant_param5=&vault=N&offer_type=null&offer_code=null&discount_value=0.0&mer_amount=100.0&eci_value=null&retry=N&response_code=0&billing_notes=&trans_date=17/03/2017 11:27:30"""
>>> s_list = s.split("&")
>>> s_list
['order_id=BW_225996', 'tracking_id=306003083135', 'bank_ref_no=1489730168508', 'order_status=Success', 'failure_message=', 'payment_mode=Net Banking', 'card_name=AvenuesTest', 'status_code=null', 'status_message=Y', 'currency=INR', 'amount=100.0', 'billing_name=test', 'billing_address=test', 'billing_city=Pune', 'billing_state=Maharashtra', 'billing_zip=411041', 'billing_country=India', 'billing_tel=1234567890', 'billing_email=test#gmail.com', 'delivery_name=test', 'delivery_address=test', 'delivery_city=Pune', 'delivery_state=Maharashtra', 'delivery_zip=411041', 'delivery_country=India', 'delivery_tel=1234567890', 'merchant_param1=3', 'merchant_param2=', 'merchant_param3=', 'merchant_param4=', 'merchant_param5=', 'vault=N', 'offer_type=null', 'offer_code=null', 'discount_value=0.0', 'mer_amount=100.0', 'eci_value=null', 'retry=N', 'response_code=0', 'billing_notes=', 'trans_date=17/03/2017 11:27:30']
>>> s_dict = {}
>>> for data in s_list:
s_dict[data.split("=")[0]] = data.split("=")[1]
>>> print s_dict
{'billing_tel': '1234567890', 'status_code': 'null', 'delivery_country': 'India', 'delivery_name': 'test', 'currency': 'INR', 'delivery_city': 'Pune', 'billing_country': 'India', 'billing_notes': '', 'retry': 'N', 'billing_email': 'test#gmail.com', 'billing_zip': '411041', 'billing_name': 'test', 'merchant_param5': '', 'order_status': 'Success', 'status_message': 'Y', 'mer_amount': '100.0', 'merchant_param3': '', 'merchant_param2': '', 'delivery_zip': '411041', 'card_name': 'AvenuesTest', 'delivery_tel': '1234567890', 'billing_address': 'test', 'order_id': 'BW_225996', 'eci_value': 'null', 'offer_code': 'null', 'merchant_param4': '', 'payment_mode': 'Net Banking', 'offer_type': 'null', 'discount_value': '0.0', 'delivery_address': 'test', 'billing_city': 'Pune', 'merchant_param1': '3', 'response_code': '0', 'failure_message': '', 'bank_ref_no': '1489730168508', 'amount': '100.0', 'trans_date': '17/03/2017 11:27:30', 'tracking_id': '306003083135', 'vault': 'N', 'delivery_state': 'Maharashtra', 'billing_state': 'Maharashtra'}
A simple loop could fix this:
a='order_id=BW_225996&tracking_id=306003083135&bank_ref_no=1489730168508&order_status=Success&failure_message=&payment_mode=Net Banking&card_name=AvenuesTest&status_code=null&status_message=Y&currency=INR&amount=100.0&billing_name=test&billing_address=test&billing_city=Pune&billing_state=Maharashtra&billing_zip=411041&billing_country=India&billing_tel=1234567890&billing_email=test#gmail.com&delivery_name=test&delivery_address=test&delivery_city=Pune&delivery_state=Maharashtra&delivery_zip=411041&delivery_country=India&delivery_tel=1234567890&merchant_param1=3&merchant_param2=&merchant_param3=&merchant_param4=&merchant_param5=&vault=N&offer_type=null&offer_code=null&discount_value=0.0&mer_amount=100.0&eci_value=null&retry=N&response_code=0&billing_notes=&trans_date=17/03/2017 11:27:30&bin_country='
dic={}
[dic.update({e.split('=')[0] : e.split('=')[1]}) for e in a.split('&')]
_str="order_id=BW_225996&tracking_id=306003083135&bank_ref_no=1489730168508&order_status=Success&failure_message=&payment_mode=Net Banking&card_name=AvenuesTest&status_code=null&status_message=Y&currency=INR&amount=100.0&billing_name=test&billing_address=test&billing_city=Pune&billing_state=Maharashtra&billing_zip=411041&billing_country=India&billing_tel=1234567890&billing_email=test#gmail.com&delivery_name=test&delivery_address=test&delivery_city=Pune&delivery_state=Maharashtra&delivery_zip=411041&delivery_country=India&delivery_tel=1234567890&merchant_param1=3&merchant_param2=&merchant_param3=&merchant_param4=&merchant_param5=&vault=N&offer_type=null&offer_code=null&discount_value=0.0&mer_amount=100.0&eci_value=null&retry=N&response_code=0&billing_notes=&trans_date=17/03/2017 11:27:30&bin_country="
{a:b for a,b in [i.split("=") for i in _str.split('&')]}
Please try this simple code, this will produce your required output,
input_string = 'order_id=BW_225996&tracking_id=306003083135&bank_ref_no=1489730168508'
splitted_string = input_string.split('&')
final_output = {}
for items in splitted_string:
dic_values = items.split('=')
final_output[dic_values[0]] = dic_values[1]
print final_output
Output:
{'order_id': 'BW_225996', 'tracking_id': '306003083135', 'bank_ref_no': '1489730168508'}
Initially we are splitting the string using '&'.
Then we are splitting every items in list using '=' as the dictionary key and
values.
Please let me know interms of any queries.
Here is a function that will do the job for you. It performs the following operations:
Break the given string into a list of strings representing key-value pairs.
Split each string representation of a key-value pair into a key and its associated value.
Insert each key and it's associated value into a dict.
parse_dict
def parse_dict(string):
dictionary = dict()
key_value_pairs = string.split('&')
for pair in key_value_pairs:
key, value = pair.split('=')
dictionary[key] = value
return dictionary
Example usage:
parsed_dict = parse_dict("order_id=BW_225996&tracking_id=306003083135")
print(parsed_dict)
Output:
{'order_id': 'BW_225996', 'tracking_id': '306003083135'}
I hope this answers your question. Happy coding!
Since this question is tagged django, this is the shortest and most correct solution:
from django.http import QueryDict
query_string = 'order_id=BW_225996&tracking_id=306003083135&bank_ref_no=1489730168508'
qdict = QueryDict(query_string) # dict like object
Unlike the other solutions, this deals with url encoding and multiple values per key automatically (use getlist()).

Categories