Saving dictionary whose keys are tuples with json, python - python

I am writing a little program in python and I am using a dictionary whose (like the title says) keys and values are tuples. I am trying to use json as follows
import json
data = {(1,2,3):(a,b,c),(2,6,3):(6,3,2)}
print json.dumps(data)
Problem is I keep getting TypeError: keys must be a string.
How can I go about doing it? I tried looking at the python documentation but didn't see any clear solution. Thanks!

You'll need to convert your tuples to strings first:
json.dumps({str(k): v for k, v in data.iteritems()})
Of course, you'll end up with strings instead of tuples for keys:
'{"(1, 2, 3)": ["a", "b", "c"], "(2, 6, 3)": [6, 3, 2]}'

If you want to load your data later on you have to postprocess it anyway. Therefore I'd just dump data.items():
>>> import json
>>> a, b, c = "abc"
>>> data = {(1,2,3):(a,b,c), (2,6,3):(6,3,2)}
>>> on_disk = json.dumps(data.items())
>>> on_disk
'[[[2, 6, 3], [6, 3, 2]], [[1, 2, 3], ["a", "b", "c"]]]'
>>> data_restored = dict(map(tuple, kv) for kv in json.loads(on_disk))
>>> data_restored
{(2, 6, 3): (6, 3, 2), (1, 2, 3): (u'a', u'b', u'c')}

You can use ujson module. ujson.dumps() accepts tuples as keys in a dictionary.
You can install ujson by pip.

For Python 3* users:
in addition to #Martijn Pieters answer,
dictonary.iteritems() is not valid, replace it with dictionary.items() :
json.dumps({str(k): v for k, v in data.items()})

Related

How to dict(zip) for every item on list?

Here is the code:
kws = [1, 2, 3]
ab = dict(zip(['keyword:'], kws))
print ab
But it only returns: {'keyword:': 1}
I want to make it return: {'keyword:': 1, 'keyword:': 2, 'keyword:': 3}
Vignesh Kalai's comment is correct, but if you just want tuples, try:
ab = zip((['keyword'] * len(kws)), kws)
python dictionaries don't support multiple keys which is what you are trying to do, but you can have a key mapped to a list. So you could have
{keyword: [1, 2, 3]}
just by doing
kws = [1,2,3]
ab = {}
ab['Keyword'] = kws
print ab
{'Keyword': [1, 2, 3]}
Dictionary can't have same key.
Sorry, it's principle of dictionary. You question is requiring a invalid result.
I know everyone doesn't like your question.
I recommend you make list-tuple object to keep your data structure. Let's try to change the method.
print [('keyword', kw) for kw in kws]
# [('keyword', 1), ('keyword', 2), ('keyword', 3)]
So, it can simulate key-value pair. I think it can satisfy your needed.

Quickest way to dedupe list in dict [duplicate]

This question already has answers here:
How do I remove duplicates from a list, while preserving order?
(31 answers)
Closed 7 years ago.
I have a dict containing lists and need a fast way to dedupe the lists.
I know how to dedupe a list in isolation using the set() function, but in this case I want a fast way of iterating through the dict, deduping each list on the way.
hello = {'test1':[2,3,4,2,2,5,6], 'test2':[5,5,8,4,3,3,8,9]}
I'd like it to appear like;
hello = {'test1':[2,3,4,5,6], 'test2':[5,8,4,3,9]}
Though I don't necessarily need to have the original order of the lists preserved.
I've tried using a set like this, but it's not quite correct (it's not iterating properly and I'm losing the first key)
for key, value in hello.items(): goodbye = {key: set(value)}
>>> goodbye
{'test2': set([8, 9, 3, 4, 5])}
EDIT: Following PM 2Ring's comment below, I'm now populating the dict differently to avoid duplicates in the first place. Previously I was using lists, but using sets prevents dupes to be appended by default;
>>> my_numbers = {}
>>> my_numbers['first'] = [1,2,2,2,6,5]
>>> from collections import defaultdict
>>> final_list = defaultdict(set)
>>> for n in my_numbers['first']: final_list['test_first'].add(n)
...
>>> final_list['test_first']
set([1, 2, 5, 6])
As you can see, the final output is a deduped set, as required.
It's not iterating wrong, you're just assigning goodbye as a new dict each time. You need to assign as an empty dict then assign the values to keys in each iteration.
goodbye = {}
for key, value in hello.items(): goodbye[key] = set(value)
>>> goodbye
{'test1': set([2, 3, 4, 5, 6]), 'test2': set([8, 9, 3, 4, 5])}
Also since sets don't preserve order, if you do want to preserve order it's best to make a simple iterating function that will return a new list that skips over already added values.
def uniqueList(li):
newList = []
for x in li:
if x not in newList:
newList.append(x)
return newList
goodbye = {}
for key, value in hello.items(): goodbye[key] = uniqueList(value)
>>> goodbye
{'test1': [2, 3, 4, 5, 6], 'test2': [5, 8, 4, 3, 9]}
You can use a list comprehension with a deduplicate function that preserves the order:
def deduplicate(seq):
seen = set()
seen_add = seen.add
return [ x for x in seq if not (x in seen or seen_add(x))]
{key: deduplicate(value) for key, value in hello.items()}
>>>hello = {'test1':[2,3,4,2,2,5,6], 'test2':[5,5,8,4,3,3,8,9]}
>>>for key,value in hello.iteritems():
hello[key] = list(set(value))
>>>hello
{'test1': [2, 3, 4, 5, 6], 'test2': [8, 9, 3, 4, 5]}
This is a more verbose way of doing it, which preserves order and works in all Python versions:
for key in hello:
s = set()
l = []
for subval in hello[key]:
if subval not in s:
l.append(subval)
s.add(subval)
hello[key] = l
my_list = [1,2,2,2,3,4,5,6,7,7,7,7,7,8,9,10]
seen = set()
print list(filter(lambda x:x not in seen and not seen.add(x),my_list))

Avoid L suffix for Long in python

I have a dictionary which may have long values for some key. I want to convert this dictionary to string and send it to a server. But when I am converting it to a string using str(dict) function for the values which have a long value is suffixed with 'L'. This when I am sending it to a server the value it is generating a problem. So can anyone suggest me a easier way of what I can do to avoid the 'L' suffix
I'm not sure what your use case is but to solve this problem and quite possibly the next problem you'll have I'd suggest using json.
import json
a = {'a': 10, 'b': 1234567812345678L}
print json.dumps(a)
# output:
{"a": 10, "b": 1234567812345678}
This is because calling str on the dict will still call repr to get the representation of it's contents.
You should just write your own function to iterate over the dict
>>> D = {10000000000000000+n:n for n in range(10)}
>>> print D
{10000000000000000L: 0, 10000000000000001L: 1, 10000000000000002L: 2, 10000000000000003L: 3, 10000000000000004L: 4, 10000000000000005L: 5, 10000000000000006L: 6, 10000000000000007L: 7, 10000000000000008L: 8, 10000000000000009L: 9}
>>> print "{{{}}}".format(', '.join("{}: {}".format(*i) for i in D.items()))
{10000000000000000: 0, 10000000000000001: 1, 10000000000000002: 2, 10000000000000003: 3, 10000000000000004: 4, 10000000000000005: 5, 10000000000000006: 6, 10000000000000007: 7, 10000000000000008: 8, 10000000000000009: 9}
Unrolling gnibbler's code is close to this:
# put all key-value-pairs into a list, formatted as strings
tmp1 = []
for i in D.items()
tmp2 = "{}: {}".format(*i)
tmp1.append(tmp2)
# create a single string by joining the elements with a comma
tmp3 = ", ".join(tmp1)
# add curly braces
tmp4 = "{{{}}}".format(tmp3)
# output result
print tmp4
The inner part of his construction is called a generator expression. They are a bit more efficient, because they don't require the temporary list (or tuple) "tmp1" and allow very terse syntax. Further, they can make code almost unreadable for people not familiar with the construct, if you have that problem try reading it from the inside out. ;^)

Obtaining length of list as a value in dictionary in Python 2.7

I have two lists and dictionary as follows:
>>> var1=[1,2,3,4]
>>> var2=[5,6,7]
>>> dict={1:var1,2:var2}
I want to find the size of the mutable element from my dictionary i.e. the length of the value for a key.
After looking up the help('dict'), I could only find the function to return number of keys i.e. dict.__len__().
I tried the Java method(hoping that it could work) i.e. len(dict.items()[0]) but it evaluated to 2.
I intend to find this:
Length of value for first key: 4
Length of value for second key: 3
when the lists are a part of the dictionary and not as individual lists in case their length is len(list).
Any suggestions will be of great help.
dict.items() is a list containing all key/value-tuples of the dictionary, e.g.:
[(1, [1,2,3,4]), (2, [5,6,7])]
So if you write len(dict.items()[0]), then you ask for the length of the first tuple of that items-list. Since the tuples of dictionaries are always 2-tuples (pairs), you get the length 2. If you want the length of a value for a given key, then write:
len(dict[key])
Aso: Try not to use the names of standard types (like str, dict, set etc.) as variable names. Python does not complain, but it hides the type names and may result in unexpected behaviour.
You can do this using a dict comprehension, for example:
>>> var1 = [1,2,3,4]
>>> var2 = [5,6,7]
>>> d = {1:var1, 2:var2}
>>> lengths = {key:len(value) for key,value in d.iteritems()}
>>> lengths
{1: 4, 2: 3}
Your "Java" method would also nearly have worked, by the way (but is rather unpythonic). You just used the wrong index:
>>> d.items()
[(1, [1, 2, 3, 4]), (2, [5, 6, 7])]
>>> d.items()[0]
(1, [1, 2, 3, 4])
>>> len(d.items()[0][1])
4
>>>for k,v in dict.iteritems():
k,len(v)
ans:-
(1, 4)
(2, 3)
or
>>>var1=[1,2,3,4]
>>>var2=[5,6,7]
>>>dict={1:var1,2:var2}
ans:-
>>>[len(v) for k,v in dict.iteritems()]
[4, 3]

Assign dict contents to independent variables

How do I split a defaultdict into independent lists with keys as listnames and values as the list elements.
For example:
defaultdict ([('A', [1, 3, 4]), ('B', [3, 6, 8])])
How do I get:
A= [1,3,4]
B= [3,6,8]
I'm sorry but generally you can't and you shouldn't try to.
One obvious reason for this is that you would need to enforce that the dict keys are valid Python names (not even any string would work, let alone dealing with non-string keys).
Another reason is, even if a key is a valid name, you could unpredictably overwrite some other object that happens to have this name. It could be a built-in function or anything, which can break your script in any possible way.
If you are not convinced, you could try something like this:
In [1]: d = {'A': [1, 3, 4], 'B': [3, 6, 8]} # a defaultdict would work, too
In [2]: for k, v in d.items():
...: globals()[k] = v
...:
In [3]: A
Out[3]: [1, 3, 4]
In [4]: B
Out[4]: [3, 6, 8]
Docs to read:
globals
locals

Categories