I have a string like:
<number>xx<->a<T>b<F>c<F>d<F>e<F>f<F>g<T>h<F>i<F>
How can I efficiently parse this string so that i.e.
xx has a value of null
a has a value of 1
b has a value of
0
You can parse that with Regular Expressions. We first remove the initial <word> at the start of the string, if it exists, and then look for pairs of word<word>, saving them into key,value pairs in a dictionary using the codes dictionary to convert _, F, T, to null, 0, 1.
import re
s = '<number>xx<->a<T>b<F>c<F>d<F>e<F>f<F>g<T>h<F>i<F>'
m = re.match(r'<(\w*?)>', s)
if m:
head = m.group(1)
s = s[m.end():]
print(head)
else:
print('No head group')
codes = {'-': 'null', 'F': '0', 'T': '1'}
pat = re.compile(r'(\w*?)<([-\w]*?)>')
out = {k: codes[v] for k, v in pat.findall(s)}
print(out)
output
number
{'xx': 'null', 'a': '1', 'b': '0', 'c': '0', 'd': '0', 'e': '0', 'f': '0', 'g': '1', 'h': '0', 'i': '0'}
Related
I tried to created a get_dict function that takes a parameter as a filename and then creates and returns a dictionary which contains
key is the number of the product code and has
value is a dictionary that contains
key is a string of sizes (S, M, L, or XL), and
value is the number of the product.
enter image description here
I tried this.
def get_dict(file_name):
d={}
e={}
with open(file_name) as f:
for line in f:
line = line.strip()
alist = line.split()
e[alist[1]] = alist[2]
d[alist[0]] = e
print (d)
the output is look like this
{'4125': {'M': '4', 'L': '7', 'XL': '3'}, '5645': {'M': '4', 'L': '7', 'XL': '3'}, '7845': {'M': '4', 'L': '7', 'XL': '3'}}
but I expect that output will be like this
{4125: {'S': 1, 'M': 4}, 5645: {'L': 7}, 9874: {'S': 8}, 9875: {'M': 8}, 7845: {'S': 10, 'XL': 3}}
Text file example
7845 XL 3
4125 S 1
5645 L 7
9874 S 3
4125 M 4
def get_dict(file_name):
d={}
with open(file_name) as f:
for line in f:
line = line.strip()
alist = line.split()
if not alist[0] in d:
d[alist[0]] = {alist[1]: alist[2]}
else:
d[alist[0]].update({alist[1]: alist[2]})
print(d)
You have to update the dictionary instead of overwriting the same key value. The above solution should work.
Output -
{'7845': {'XL': '3'}, '4125': {'S': '1', 'M': '4'}, '5645': {'L': '7'}, '9874': {'S': '3'}}
I want to reload my JSON after my text file is updated by reopening the text file.
import json
with open('np.txt') as np:
np_data = np.read()
np_list=json.loads(np_data)
def reopen_file():
print("reloading")
with open('np.txt') as np:
np_data = np.read()
np_list=json.loads(np_data)
y=1
while(y==1):
#np.flush()
#reopen_file()
x=input("input: ")
print("your input is" +x)
if(int(x)==1):
print(np_list)
y=input("continue?: ")
reopen_file()
print(np_list)
OUTPUT:
I update the text file before entering the value for 'y'(continue?), but the output remains the same. (I am editing the file manually)
np.txt:
{"a":"1",
"b":"2",
"c":"3",
"d":"4",
"e":"5",
"f":"6",
"g":"7",
"h":"8",
"i":"9"}
As I already commented, your code is not actually updating the same np_list you are using. A quick and dirty example to show this is just adding a print(np_list) at the end of reopen_file:
input: 1
your input is1
{'e': '5', 'b': '2', 'd': '4', 'f': '5', 'c': '3', 'a': '1', 'h': '8', 'i': '9', 'g': '7'}
continue?: 1
reloading
{'e': '5', 'b': '2', 'd': '4', 'f': '6', 'c': '3', 'a': '1', 'h': '8', 'i': '9', 'g': '7'}
{'e': '5', 'b': '2', 'd': '4', 'f': '5', 'c': '3', 'a': '1', 'h': '8', 'i': '9', 'g': '7'}
This solution works fine:
import json
def reopen_file():
with open('np.txt') as np:
np_data = np.read()
return json.loads(np_data)
np_list=reopen_file()
y=1
while(y==1):
#np.flush()
#reopen_file()
x=input("input: ")
print("your input is" +x)
if(int(x)==1):
print(np_list)
y=int(input("continue?: "))
np_list = reopen_file()
Which outputs:
Python-reload-file> python test.py
input: 1
your input is1
{'d': '4', 'b': '2', 'f': '5', 'h': '8', 'e': '5', 'a': '1', 'c': '3', 'i': '9', 'g': '7'}
continue?: 1
input: 1
your input is1
{'d': '4', 'b': '2', 'f': '6', 'h': '8', 'e': '5', 'a': '1', 'c': '3', 'i': '9', 'g': '7'}
continue?:
np_list is declared as a global variable that you can't overwrite without using the global keyword. Simplified example:
a = 3
def change_a():
a = 4
print("inside:", a)
print("outside:", a)
change_a()
print("outside after:", a)
output:
outside: 3
inside: 4
outside after: 3
example using the global keyword: (don't do this if you have other options like making a class)
a = 3
def change_a():
global a
a = 4
print("inside:", a)
print("outside:", a)
change_a()
print("outside after:", a)
output:
outside: 3
inside: 4
outside after: 4
Another small hint about how you read your json file: instead of doing
import json
with open('np.txt') as np:
np_data = np.read()
np_list=json.loads(np_data)
you can just
with open("np.txt") as np:
np_list = json.load(np)
Suppose, there is a dictionary like
my_dict = {'A': {'5', '7', '9', '3'},
'B': {'4', '8','3'},
'C': {'5', '3', '2', '9'},
'D': {'1','6', '8','3'},
'E': {'4','3','5'}}
Now the output should be like {A,C} because they have most number of common values.
dct = {'A': {'5', '7', '9', '3'}, 'B': {'4', '8','3'}, 'C': {'5', '3', '2', '9'}, 'D': {'1','6', '8','3'}, 'E': {'4','3','5'}}
ans = [None, None]
mx = 0
for i in dct:
for j in dct:
if i != j and len(dct[i].intersection(dct[j])) > mx:
ans = [i, j]
mx = len(dct[i].intersection(dct[j]))
As there are sets contained, to find number of common elements, we have intersection method.
>>> ans
['A', 'C']
Although, its worth noting that this code would always produce a pair. If you want more number of elements, the number of loops is going to increase accordingly.
I have a list of dictionaries -
list1 = [{'id' : '1', 'b' : '2', 'c' : '3'}, {'id' : '4', 'b' : '5', 'c' : '6'}, {'id' : '7', 'b' : '8', 'c' : ''}]
Based on the value of c being null or not, I am making a call which returns -
list2 - {'d' : '30', 'id' : 1}, {'d': '25', 'id' : '4'}
Now I want to modify list1, so that the final list has the values of d for the ids which have c. For example -
list1 = [{'id' : '1', 'b' : '2', 'c' : '3', 'd' : '30'}, {'id' : '4', 'b' : '5', 'c' : '6', 'd' : '25'}, {'id' : '7', 'b' : '8', 'c' : ''}]
My approach -
for l in list2:
current_list = {}
for l2 in list1:
if l2['id'] == l['id']:
current_list = l2
break
if current_list:
current_list['d'] = l['d']
Here the actual dict is not getting modified. How can I modify the actual list? Also, is there a neater way to do this?
I'm not certain I understand what you are trying to accomplish. Your written description of your goal does not agree with you code. Based on the code, I'm guessing that you want to match up the data based on the id values.
# You've got some dicts.
dicts = [
{'id': '1', 'b': '2', 'c': '3'},
{'id': '4', 'b': '5', 'c': '6'},
{'id': '7', 'b': '8', 'c': ''},
]
# You've got some other dicts having the same IDs.
d_dicts = [
{'d': '30', 'id': '1'},
{'d': '25', 'id': '4'},
]
# Reorganize that data into a dict, keyed by ID.
dlookup = {d['id'] : d['d'] for d in d_dicts}
# Now add that lookup data to the main list of dicts.
for d in dicts:
i = d['id']
if i in dlookup:
d['d'] = dlookup[i]
Assuming mr FMc are correct, there is in python 3.5 a valid approach to merge dicts. Which in this case would led us to:
dicts = [
{'id': '1', 'b': '2', 'c': '3'},
{'id': '4', 'b': '5', 'c': '6'},
{'id': '7', 'b': '8', 'c': ''},
]
d_dicts = [
{'d': '30', 'id': '1'},
{'d': '25', 'id': '4'},
]
dicts = [{**d, **dict(*filter(lambda x: x["id"] == d["id"], d_dicts))} for d in dicts]
I like these kinda expressions instead of writing it all out, but it has the "benefit" of crashing instead of overwriting stuff when there is more then one dict with the same id. But my solution still overwrites values if there are duplicate keys silently. The inserted value being the value from whatever's second in the dict merge.
For example i have dict python
dict = {'a': '1', 'b': '2', 'c': '3'}
and array
arr = ['4', '5', '6']
I want add sequential value array to dict
dict1 = {'a': '4', 'b': '5', 'c': '6'}
Please suggest a specific solution.
>>> d = {'a': '1', 'b': '2', 'c': '3'}
>>> arr = ['4', '5', '6']
>>> dict(zip(sorted(d), arr))
{'a': '4', 'c': '6', 'b': '5'}
You can use zip:
>>> import string
>>> arr = ['4', '5', '6']
>>> # dict(zip(sorted(original_dict), arr))
>>> dict(zip(string.ascii_lowercase, arr))
{'b': '5', 'c': '6', 'a': '4'}
BTW, don't name a varialbe dict. It will shadows builtin type/function dict.
Not sure what you are trying to do, but the below code snippet does what you intend in your question.
import os
dict = {'a': '1', 'b': '2', 'c': '3'}
arr = ['4', '5', '6']
dict1 = {}
dictAsList = dict.items()
i = 0
for key in sorted(dict):
try:
dict1[key] = arr[i]
except:
pass
i = i+1
print dict1
Python dictionary doesn't have order. So I don't get what sequential means in dictionary.
If you just want to set all value to another value you can do like this.
d = {'a': '1', 'b': '2', 'c': '3'}
arr = ['4', '5', '6']
print dict(zip(d.keys(), arr))
#{'a': '4', 'c': '5', 'b': '6'}
If you want to set value as same order you can do like this.(You need change your data structure)
from collections import OrderedDict
d = OrderedDict([('a', '1'), ('b', '2'), ('c', '3')])
arr = ['4', '5', '6']
print dict(zip(d.keys(), arr))
#{'a': '4', 'c': '6', 'b': '5'}