convert list of key/value strings into map python - python-3.x

Convert list of key/value strings into map. Assume that the list contains only strings and that each string has exactly one ':' .
Is the following code a good approach? Does anyone know of a more elegant solution to this?
>>> l = ['name:number']
>>> l = {x[:x.find(':')] : x[x.find(':')+1:] for x in l}
>>> print(l)
{'name': 'number'}

An even simpler approach:
>>> l = ['name:number']
>>> dict(x.split(':') for x in l)
{'name': 'number'}

Related

Reading input as dictionary in python

Im trying to read input spread across multiline in form of dictionary and apply simple math operations on the value of dictionary . My code reads
d ={}
bal=0
text = input().split(",") #split the input text based on line'text'
print(text)
for i in range(5):
text1 = text[i].split(" ") #split the input text based on space & store in the list 'text1'
d[text1[0]] = int(text1[1]) #assign the 1st item to key and 2nd item to value of the dictionary
print(d)
for key in d:
if key=='D':
bal=bal+int(d[key])
#print(d[key])
elif key=='W':
bal=bal-int(d[key])
print(bal)
Input : W 300,W 200,D 100,D 400,D 600
output :{'D': 600, 'W': 200}
400
Expected Output: {'W':300,'W':200,'D':100,'D':400,'D':600}
600
ISSUE: The issue here is the code always reads 2 and last values only . For example in the above case output is
{'D': 600, 'W': 200}
400
Can someone let me know the issue with for loop .
Thanks in advance
You can try like this in a simpler way using your own approach. #Rakesh and #Sabesh suggested good. Dictionary is an unordered collection with unique and immutable keys. You can easily check this on your Python interactive console by executing help(dict).
You can check https://docs.python.org/2/library/collections.html#collections.defaultdict . Here you'll find number of examples on how to efficiently using dictionary.
>>> d = {}
>>> text = 'W 300,W 200,D 100,D 400,D 600'
>>>
>>> for item in text.split(","):
... arr = item.split()
... d.setdefault(arr[0], []).append(arr[1])
...
>>> d
{'W': ['300', '200'], 'D': ['100', '400', '600']}
>>>
>>> w = [int(n) for n in d['W']]
>>> d = [int(n) for n in d['D']]
>>>
>>> bal = sum(d) - sum(w)
>>> bal
600
>>>

If I have duplicates in a list with brackets, what should I do

Suppose I have the following list:
m=[1,2,[1],1,2,[1]]
I wish to take away all duplicates. If it were not for the brackets inside the the list, then I could use:
m=list(set(m))
but when I do this, I get the error:
unhashable type 'set'.
What command will help me remove duplicates so that I could only be left with the list
m=[1,2,[1]]
Thank you
You can do something along these lines:
m=[1,2,[1],1,2,[1]]
seen=set()
nm=[]
for e in m:
try:
x={e}
x=e
except TypeError:
x=frozenset(e)
if x not in seen:
seen.add(x)
nm.append(e)
>>> nm
[1, 2, [1]]
From comments: This method preserves the order of the original list. If you want the numeric types in order first and the other types second, you can do:
sorted(nm, key=lambda e: 0 if isinstance(e, (int,float)) else 1)
The first step will be to convert the inner lists to tuples:
>> new_list = [tuple(i) if type(i) == list else i for i in m]
Then create a set to remove duplicates:
>> no_duplicates = set(new_list)
>> no_duplicates
{1, 2, (1,)}
and you can convert that into list if you wish.
For a more generic solution you can serialize each list item with pickle.dumps before passing them to set(), and then de-serialize the items with pickle.loads:
import pickle
m = list(map(pickle.loads, set(map(pickle.dumps, m))))
If you want the original order to be maintained, you can use a dict (which has become ordered since Python 3.6+) instead of a set:
import pickle
m = list(map(pickle.loads, {k: 1 for k in map(pickle.dumps, m)}))
Or if you need to be compatible with Python 3.5 or earlier versions, you can use collections.OrderedDict instead:
import pickle
from collections import OrderedDict
m = list(map(pickle.loads, OrderedDict((k, 1) for k in map(pickle.dumps, m))))
result = []
for i in m:
flag = True
for j in m:
if i == j:
flag = False
if flag:
result.append(i)
Result will be: [1,2,[1]]
There are ways to make this code shorter, but I'm writing it more verbosely for readability. Also, note that this method is O(n^2), so I wouldn't recommend for long lists. But benefits is the simplicity.
Simple Solution,
m=[1,2,[1],1,2,[1]]
l= []
for i in m:
if i not in l:
l.append(i)
print(l)
[1, 2, [1]]
[Program finished]

testing if the values of a dictionary are non zero with all() function

I use Python 3
I want to check if all of my tested values in the nested dictionary are non 0.
So here is the simplified example dict:
d = {'a': {'1990': 10, '1991': 0, '1992': 30},
'b': {'1990': 15, '1991': 40, '1992': 0}}
and I want to test if for both dicts 'a' and 'b' the values of the keys '1990' and '1991' are not zero
for i in d:
for k in range(2):
year = 1990
year = year + k
if all((d[i][str(year)]) != 0):
print(d[i])
so it should only return b, because a['1991']=0
but this is the first time I work with the all() function and I get the error core: TypeError: 'bool' object is not iterable
the error is in the if all() line
thank you very much!
This can done a bit more generally with a list comprehension where you iterate over the items in dict d. A simple comprehension to iterate over the keys and values in our dictionary looks like this:
>>> [k for k, v in d.items()]
['a', 'b']
In the above k will contain the keys and v the values. The comprehension also has an if clause. With that you can filter out the items you don't want. So we define years = ('1990', '1991'). Now we can do another comprehension to test our year values.
To iterate over only 'a', we could do this:
>>> [d['a'][y] for y in years]
[10, 0]
>>> all([d['a'][y] for y in years])
False
Gluing the whole thing together:
>>> d={'a' :{ '1990': 10, '1991':0, '1992':30},'b':{ '1990':15, '1991':40, '1992':0}}
>>> years = ('1990', '1991')
>>> [k for k, v in d.items() if all([v[y] for y in years])]
['b']
See the python docs for more information on list comprehensions.

Translating for loop into list comprehension

I can get this loop to work properly:
for x in range(0,len(l)):
for k in d:
if l[x] in d[k]:
l[x] = k
This looks through a list and checks if the value is in any of the dictionary items and then calculates it equal to the dictionary key it is found within (the dictionary contains lists.)
However, I want to convert to a list comprehension or other single line statement for use in a pandas dataframe - to populate a field based on whether or not another field's value is in the labeled dictionary keys and assign it the dictionary key value.
Here is my best attempt, but it does not work:
l = [ k for x in range(0,len(l)) if l[x] in d[k] for k in d ]
Thanks
Assuming I understand what you're after (example data that can be copied and pasted is always appreciated), I'd do something like this:
>>> l = ["a", "b", "c", "d"]
>>> d = {1: ["a"], 3: ["d", "c"]}
>>> l2 = [next((k for k,v in d.items() if lx in v), lx) for lx in l]
>>> l2
[1, 'b', 3, 3]
Don't forget to think about what behaviour you want if an entry in l is found in multiple lists in d, of course, although that may not be an issue with your data.
You can't do it with a list comprehension, because you have an assignment:
l[x] = k
which is an statement, and a list comprehension can't have them.

How to turn a string lists into a lists?

There are other threads about turning strings inside a lists into different data types. I want to turn a string that is in the form of a lists into a lists. Like this: "[5,1,4,1]" = [5,1,4,1]
I need this because I am writing a program that requires the user to input a lists
Example of problem:
>>> x = input()
[3,4,1,5]
>>> x
'[3,4,1,5]'
>>> type(x)
<class 'str'>
If you mean evaluate python objects like this:
x = eval('[3,4,1,5]');
print (x);
print(type(x) is list)
[3, 4, 1, 5]
True
Use this with caution as it can execute anything user will input. Better use a parser to get native lists. Use JSON for input and parse it.
Use eval() for your purpose. eval() is used for converting code within a string to real code:
>>> mystring = '[3, 5, 1, 2, 3]'
>>> mylist = eval(mystring)
>>> mylist
[3, 5, 1, 2, 3]
>>> mystring = '{4: "hello", 2:"bye"}'
>>> eval(mystring)[4]
'hello'
>>>
Use exec() to actually run functions:
>>> while True:
... inp = raw_input('Enter your input: ')
... exec(inp)
...
Enter your input: print 'hello'
hello
Enter your input: x = 1
Enter your input: print x
1
Enter your input: import math
Enter your input: print math.sqrt(4)
2.0
In your scenario:
>>> x = input()
[3,4,1,5]
>>> x = eval(x)
>>> x
[3, 4, 1, 5]
>>> type(x)
<type 'list'>
>>>
Thanks for your input guys, but I would prefer not to eval() because it is unsafe.
Someone actually posted the answer that allowed me to solve this but then they deleted it. I am going to reposts that answer:
values = input("Enter values as lists here")
l1 = json.loads(values)
You can use ast.literal_eval for this purpose.
Safely evaluate an expression node or a string containing a Python
expression. The string or node provided may only consist of the
following Python literal structures: strings, bytes, numbers, tuples,
lists, dicts, sets, booleans, and None.
This can be used for safely evaluating strings containing Python
expressions from untrusted sources without the need to parse the
values oneself.
>>> import ast
>>> val = ast.literal_eval('[1,2,3]')
>>> val
[1, 2, 3]
Just remember to check that it's actually a list:
>>> isinstance(val, list)
True

Resources