I have a text file below:
A test B echo C delete
A test B echo C delete D modify
A test B echo C delete
I want to parse the text file above, translate to list of list, and then to a dictionary.
Expected list of list is:
[['A', 'test', 'B', 'echo', 'C', 'delete'], ['A', 'test', 'B', 'echo', 'C', 'delete', 'D', 'modify'], ['A', 'test', 'B', 'echo', 'C', 'delete']]
Final result for dictionary is:
[{'A':'test','B':'echo','C':'delete'},{'A':'test','B':'echo','C':'delete','D': 'modify'},{'A':'test', 'B':'echo', 'C':'delete'}]
This is my script:
#!/usr/bin/python3
def listToDict(list):
listDict = {list[i]: list[i + 1] for i in range (0, len(list), 2)}
return listDict
def parse_file(filepath):
string_to_listoflist = []
with open(filepath, 'r') as file_object:
lines = file_object.readlines()
for line in lines:
string_to_listoflist.append(line.rstrip().split())
dictionary = listToDict(string_to_listoflist)
print(dictionary)
if __name__ == '__main__':
filepath = 'log.txt'
parse_file(filepath)
with the above script will produce an error below:
Traceback (most recent call last):
File "parse.py", line 19, in <module>
parse_file(filepath)
File "parse.py", line 14, in parse_file
dictionary = listToDict(string_to_listoflist)
File "parse.py", line 4, in listToDict
listDict = {list[i]: list[i + 1] for i in range (0, len(list), 2)}
File "parse.py", line 4, in <dictcomp>
listDict = {list[i]: list[i + 1] for i in range (0, len(list), 2)}
TypeError: unhashable type: 'list'
Now I create another loop in the list of list below:
#!/usr/bin/python3
def listToDict(list):
listDict = {list[i]: list[i + 1] for i in range (0, len(list), 2)}
return listDict
def parse_file(filepath):
string_to_listoflist = []
dictionary = {}
with open(filepath, 'r') as file_object:
lines = file_object.readlines()
for line in lines:
string_to_listoflist.append(line.rstrip().split())
for e in string_to_listoflist:
dictionary = listToDict(e)
print(dictionary)
if __name__ == '__main__':
filepath = 'log.txt'
parse_file(filepath)
The script above will produce unexpected result even I define the dictionary variable before the loop:
{'A': 'test', 'B': 'echo', 'C': 'delete'}
Then change the position of print command as below:
#!/usr/bin/python3
def listToDict(list):
listDict = {list[i]: list[i + 1] for i in range (0, len(list), 2)}
return listDict
def parse_file(filepath):
string_to_listoflist = []
dictionary = {}
with open(filepath, 'r') as file_object:
lines = file_object.readlines()
for line in lines:
string_to_listoflist.append(line.rstrip().split())
for e in string_to_listoflist:
dictionary = listToDict(e)
print(dictionary)
if __name__ == '__main__':
filepath = 'log.txt'
parse_file(filepath)
Unexpected result for the script above is:
{'A': 'test', 'B': 'echo', 'C': 'delete'}
{'A': 'test', 'B': 'echo', 'C': 'delete', 'D': 'modify'}
{'A': 'test', 'B': 'echo', 'C': 'delete'}
Can anyone help how to resolve my issue?
Thanks
In your first attempt, your variable string_to_listoflist is a list of lists.
When you pass it to your function listToDict, the function iterates on the parent level of the list instead of iterating over each list within the parent list. Thus, the first entry attempted in the dictionary is
['A', 'test', 'B', 'echo', 'C', 'delete']:['A', 'test', 'B', 'echo', 'C', 'delete', 'D', 'modify']
rather than your intended
'A':'test'
This causes the error you observe TypeError: unhashable type: 'list' since a list (mutable) is attempted to be used as a key in a dictionary, which requires immutable keys.
Adding the extra loop surrounding each element of the parent list is the correct way to resolve this. However, if you want your final result to be inside a list, you simply need to append the result to a list.
In other words, perhaps the following
dictionaries=[]
for e in string_to_listoflist:
dictionary = listToDict(e)
dictionaries.append(dictionary)
print(dictionaries)
You can use re module to obtain your desired dict.
For example:
import re
with open('file.txt', 'r') as f_in:
out = [dict(re.findall(r'([A-Z]+) ([^\s]+)', line)) for line in f_in]
print(out)
Prints:
[{'A': 'test', 'B': 'echo', 'C': 'delete'}, {'A': 'test', 'B': 'echo', 'C': 'delete', 'D': 'modify'}, {'A': 'test', 'B': 'echo', 'C': 'delete'}]
Related
I have a list of dictionaries in the form:
my_list = [{'a': 'Jane', 'b': 32}, {'a': 'Jack', 'b': 54}]
I want to re-order this to the form:
new_dt = [{'b': 32, 'a': 'Jane'}, {'b': 54, 'a': 'Jack'}]
I have used the following code:
order_dict = ['b', 'a']
for dt in my_list:
for k in order_dict:
new_dt = my_list[k]
Traceback
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-87-0d451ee34800> in <module>
3 for dt in my_list:
4 for k in order_dict:
----> 5 new_dt = my_list[k]
TypeError: list indices must be integers or slices, not str
You can simply do a:
my_list = [{'a': 'Jane', 'b': 32}, {'a': 'Jack', 'b': 54}]
print([dict(sorted(x.items(),key = lambda x:x[0],reverse=True)) for x in my_list])
The OUTPUT:
[{'b': 32, 'a': 'Jane'}, {'b': 54, 'a': 'Jack'}]
Explanation
sorted(x.items(),key = lambda x:x[0],reverse=True)
Here we are just sorting the items (keys and values) in the dictionary to get the order as required.
key = lambda x:x[0]
This component ensures that we are sorting based on the first element in items(essentially the key of dictionary)
We have reverse Set to true to get the desired sequence.
I want to flat a list that has nested and not nested elements. From this solution I've tried and it works if all elements within mylist were lists, but
in mylist I have simple text strings and nested lists.
My list is like this:
mylist = [
'tz',
'7',
['a', 'b', 'c'],
[['2'], ['4', 'r'], ['34']],
[['7'], ['3', ['2', ['1']]], ['9']],
[['11',['7','w']], 'U1', ['0']]
]
And my current code is this, getting the error below:
import collections#.abc
def flatten(l):
for el in l:
if isinstance(el, collections.Iterable) and not isinstance(el, (str, bytes)):
yield from flatten(el)
else:
yield el
mylist1=[list(flatten(sublist)) if type(sublist) is list else sublist for sublist in mylist]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <listcomp>
File "<stdin>", line 3, in flatten
TypeError: isinstance() arg 2 must be a type or tuple of types
>>>
My expected output would be like this
mylist1 = [
'tz',
'7',
['a', 'b', 'c'],
['2', '4', 'r','34'],
['7','3','2','1','9'],
['11','7','w','U1','0']
]
What is missing to fix this? thanks.
UPDATE
Now I'm getting this error with code suggested by #Alok
>>> for item in mylist:
... # if the item in mylist is a list, pass it to your flatten method else
... # add it to the final list
... if isinstance(item, list):
... final_list.append(list(flatten(item)))
... else:
... final_list.append(item)
...
Traceback (most recent call last):
File "<stdin>", line 5, in <module>
File "<stdin>", line 3, in flatten
TypeError: isinstance() arg 2 must be a type or tuple of types
The problem is with some instances which I will point out:
Python 3.x is not following collections.Iterable anymore, you need to import the items from collections.abc and always do try-catch for any import error
try:
from collections.abc import Iterable
except ImportError:
from collections import Iterable
Not utilizing your flatten method appropriately, the method, returns the data, but you have to store it in the form of a list and append it to the final answer list YOUR SUB ARRAYS ONLY BE PASSED INTO THIS METHOD
data.append(list(flatten(item)))
FINAL SOLUTION:
try:
from collections.abc import Iterable
except ImportError:
from collections import Iterable
mylist = [
'tz',
'7',
['a', 'b', 'c'],
[['2'], ['4', 'r'], ['34']],
[['7'], ['3', ['2', ['1']]], ['9']],
[['11',['7','w']], 'U1', ['0']]
]
def flatten(l):
for el in l:
if isinstance(el, Iterable) and not isinstance(el, (str, bytes)):
yield from flatten(el)
else:
yield el
final_list = []
for item in mylist:
# if the item in mylist is a list, pass it to your flatten method else
# add it to the final list
if isinstance(item, type([])): final_list.append(list(flatten(item)))
else: final_list.append(item)
print(final_list)
OUTPUT
['tz', '7', ['a', 'b', 'c'], ['2', '4', 'r', '34'], ['7', '3', '2', '1', '9'], ['11', '7', 'w', 'U1', '0']]
I hope you can achieve your desired output in this way.
I have a text file that I am trying to write to a JSON file. Some of the values are returned as None, True or False. I need to replace None with "None" (string), True with "True" and False with "False"
I tried adding the line
data=data.replace(None,"None")
However, I get an error
Traceback (most recent call last):
File "parse_get_drivers.py", line 17, in <module>
data=data.replace(None,"None")
TypeError: replace() argument 1 must be str, not None
Here is my script
import json
import re
from pprint import pprint
import pandas as pd
inHandler = open('get_drivers.txt', 'r')
outHandler = open('drivers.json', 'w')
data = ''
for line in inHandler.readlines():
print('src:' + line)
line = line.replace("}]},","}]},\r")
data += line
print('replace:' + line)
data=data.replace("'", '"')
data=data.replace(None,"None")
outHandler.write(data)
inHandler.close()
outHandler.close()
The required result is to replace None, True and False values with "None", "True" and "False".
You should parse the input as JSON instead of parsing it line by line as separate strings, so that you can recursively traverse the data structure to replace None (or in JSON's terms, null) with "None":
def replace(data, search, replacement, parent=None, index=None):
if data == search:
parent[index] = replacement
elif isinstance(data, (list, dict)):
for index, item in enumerate(data) if isinstance(data, list) else data.items():
replace(item, search, replacement, parent=data, index=index)
so that:
import json
d = json.loads('{"a": 1, "b": [1, null], "c": {"d": null}}')
print(d)
replace(d, None, 'None')
print(d)
print(json.dumps(d))
outputs:
{'a': 1, 'b': [1, None], 'c': {'d': None}}
{'a': 1, 'b': [1, 'None'], 'c': {'d': 'None'}}
{"a": 1, "b": [1, "None"], "c": {"d": "None"}}
for example:
s = 'abc'
number = 1
I want to write a function that return a dict like {'a': {'a', 'b'}, 'b': {'a', 'b', 'c'}, 'c': {'b', 'c'}}
number determine how many adjacent letters next to the current key.
def test(s : str, num : int) -> {str:{str}}:
dict = {}
for word in s:
dict[word] = word
return dict
i can only write one return the same key and value. any suggestions?
Try something like:
>>> s='abc'
>>> n=1
>>> {c:{e for e in[s[i-n:i],c,s[i+1:i+1+n]] if e} for i, c in enumerate(s)}
{'a': {'a', 'b'}, 'b': {'a', 'b', 'c'}, 'c': {'b', 'c'}}
I have this example code and nee to print out e.g. the second argument position alone, how do i do it?
def fun(a, b, c):
d = locals()
e = d
print (e)
print (locals())
fun(None, 2, None)
print(b) ... or I do not understand the question.
Update: If you mean to know the names of the arguments, you may want to use the standard module named inspect. Try the following:
#!python3
import inspect
def fun(a, b, c):
d = locals()
e = d
print (e)
print (locals())
# Here for observing from inside.
argspec = inspect.getfullargspec(fun)
print(argspec.args)
for arg in argspec.args:
print('argument', repr(arg), '=', repr(d[arg]))
# You can use indexing of the arg names if you like. Then the name
# is used for looking in locals() -- here you have it in d.
args = argspec.args
print(d[args[0]])
print(d[args[1]])
print(d[args[2]])
fun(None, 2, None)
# Here for observing from outside.
argspec = inspect.getfullargspec(fun)
print(argspec.args)
for n, arg in enumerate(argspec.args, 1):
print('argument', n, 'is named', repr(arg))
You should observe:
{'a': None, 'b': 2, 'c': None}
{'d': {...}, 'e': {...}, 'a': None, 'b': 2, 'c': None}
['a', 'b', 'c']
argument 'a' = None
argument 'b' = 2
argument 'c' = None
None
2
None
['a', 'b', 'c']
argument 1 is named 'a'
argument 2 is named 'b'
argument 3 is named 'c'
See the doc http://docs.python.org/3.3/library/inspect.html#inspect.getfullargspec