I have a dictionary like this:
dict1 = {0: set([1, 4, 5]), 1: set([2, 6]), 2: set([3]), 3: set([0]), 4: set([1]), 5: set([2]), 6: set([])}
and from this dictionary I want to build another dictionary that count the occurrences of keys in dict1 in every other value ,that is the results should be:
result_dict = {0: 1, 1: 2, 2: 2, 3: 1, 4: 1, 5: 1, 6: 1}
My code was this :
dict1 = {0: set([1, 4, 5]), 1: set([2, 6]), 2: set([3]), 3: set([0]), 4: set([1]), 5:set([2]), 6: set([])}
result_dict = {}
for pair in dict1.keys():
temp_dict = list(dict1.keys())
del temp_dict[pair]
count = 0
for other_pairs in temp_dict :
if pair in dict1[other_pairs]:
count = count + 1
result_dict[pair] = count
The problem with this code is that it is very slow with large set of data.
Another attempt was in a single line, like this :
result_dict = dict((key ,dict1.values().count(key)) for key in dict1.keys())
but it gives me wrong results, since values of dict1 are sets:
{0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0}
thanks a lot in advance
I suppose, for a first stab, I would figure out which values are there:
all_values = set().union(*dict1.values())
Then I'd try to count how many times each value occurred:
result_dict = {}
for v in all_values:
result_dict[v] = sum(v in dict1[key] for key in dict1)
Another approach would be to use a collections.Counter:
result_dict = Counter(v for set_ in dict1.values() for v in set_)
This is probably "cleaner" than my first solution -- but it does involve a nested comprehension which can be a little difficult to grok. It does work however:
>>> from collections import Counter
>>> dict1
{0: set([1, 4, 5]), 1: set([2, 6]), 2: set([3]), 3: set([0]), 4: set([1]), 5: set([2]), 6: set([])}
>>> result_dict = Counter(v for set_ in dict1.values() for v in set_)
Just create a second dictionary using the keys from dict1, with values initiated at 0. Then iterate through the values in the sets of dict1, incrementing values of result_dict as you go. The runtime is O(n), where n is the aggregate number of values in sets of dict1.
dict1 = {0: set([1, 4, 5]), 1: set([2, 6]), 2: set([3]), 3: set([0]), 4: set([1]), 5:set([2]), 6: set([])}
result_dict = dict.fromkeys(dict1.keys(), 0)
# {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0}
for i in dict1.keys():
for j in dict1[i]:
result_dict[j] += 1
print result_dict
# {0: 1, 1: 2, 2: 2, 3: 1, 4: 1, 5: 1, 6: 1}
Related
dic = {1: 1, 3: 3, 5: 6, 6: 6}
new_mappping is reverse from dic {1: [1], 3: [3], 6: [5, 6]}
for keys, values in new_mapping.items():
if keys not in new_sort.items():
if values not in new_sort.items():
new_sort = new_mapping
for keys,values in new_sort.items():
lens = len(values)
ky = {keys: values}
lll[lens] = ky
output from code:
{1: {3: [3]}, 2: {6: [5, 6]}}
desired output:
{1: {1: [1], 3: [3]}, 2: {6: [5, 6]}}
Code:
#INPUT
dic = {1: 1, 3: 3, 5: 6, 6: 6}
#Step 1 - change keys to values and values to keys
rev_dic={}
[rev_dic.update({v: rev_dic[v]+[k]}) if v in rev_dic else rev_dic.update({v: [k]}) for k, v in dic.items()]
#Step 2 - create new dictionary by list length
new_dic = {k:{} for k in range(1,max([len(v) for v in rev_dic.values()])+1)}
#Lastly, insert the dictionary in new_dic by dics' value list length
[new_dic[len(val)].update({key:val}) for key,val in rev_dic.items()]
new_dic
Output:
{1: {1: [1], 3: [3]}, 2: {6: [5, 6]}}
This question already has answers here:
How do I count the occurrences of a list item?
(30 answers)
Closed 3 years ago.
I am trying to track seen elements, from a big array, using a dict.
Is there a way to force a dictionary object to be integer type and set to zero by default upon initialization?
I have done this with a very clunky codes and two loops.
Here is what I do now:
fl = [0, 1, 1, 2, 1, 3, 4]
seenit = {}
for val in fl:
seenit[val] = 0
for val in fl:
seenit[val] = seenit[val] + 1
Of course, just use collections.defaultdict([default_factory[, ...]]):
from collections import defaultdict
fl = [0, 1, 1, 2, 1, 3, 4]
seenit = defaultdict(int)
for val in fl:
seenit[val] += 1
print(fl)
# Output
defaultdict(<class 'int'>, {0: 1, 1: 3, 2: 1, 3: 1, 4: 1})
print(dict(seenit))
# Output
{0: 1, 1: 3, 2: 1, 3: 1, 4: 1}
In addition, if you don't like to import collections you can use dict.get(key[, default])
fl = [0, 1, 1, 2, 1, 3, 4]
seenit = {}
for val in fl:
seenit[val] = seenit.get(val, 0) + 1
print(seenit)
# Output
{0: 1, 1: 3, 2: 1, 3: 1, 4: 1}
Also, if you only want to solve the problem and don't mind to use exactly dictionaries you may use collection.counter([iterable-or-mapping]):
from collections import Counter
fl = [0, 1, 1, 2, 1, 3, 4]
seenit = Counter(f)
print(seenit)
# Output
Counter({1: 3, 0: 1, 2: 1, 3: 1, 4: 1})
print(dict(seenit))
# Output
{0: 1, 1: 3, 2: 1, 3: 1, 4: 1}
Both collection.defaultdict and collection.Counter can be read as dictionary[key] and supports the usage of .keys(), .values(), .items(), etc. Basically they are a subclass of a common dictionary.
If you want to talk about performance I checked with timeit.timeit() the creation of the dictionary and the loop for a million of executions:
collection.defaultdic: 2.160868141 seconds
dict.get: 1.3540439499999999 seconds
collection.Counter: 4.700308418999999 seconds
collection.Counter may be easier, but much slower.
You can use collections.Counter:
from collections import Counter
Counter([0, 1, 1, 2, 1, 3, 4])
Output:
Counter({1: 3, 0: 1, 2: 1, 3: 1, 4: 1})
You can then address it like a dictionary:
>>> Counter({1: 3, 0: 1, 2: 1, 3: 1, 4: 1})[1]
3
>>> Counter({1: 3, 0: 1, 2: 1, 3: 1, 4: 1})[0]
1
Using val in seenit is a bit faster than .get():
seenit = dict()
for val in fl:
if val in seenit :
seenit[val] += 1
else:
seenit[val] = 1
For larger lists, Counter will eventually outperform all other approaches. and defaultdict is going to be faster than using .get() or val in seenit.
in python, if I want to find the max value of d, but the key only include 1,2,3 other than all the keys in the d. so how to do, thank you.
d = {1: 5, 2: 0, 3: 4, 4: 0, 5: 1}
Just get the keys and values for the keys 1, 2 and 3 in a list of tuples, sort the list and get the first tuple element [0] key [0].
d = {1: 5, 2: 0, 3: 4, 4: 0, 5: 1}
key_max_val = sorted([(k,v) for k,v in d.items() if k in [1,2,3]])[0][0]
print(key_max_val) # Outputs 1
You can use operator:
It will return you the key with maximum value:
In [873]: import operator
In [874]: d = {1: 5, 2: 0, 3: 4, 4: 0, 5: 1}
In [875]: max(d.iteritems(), key=operator.itemgetter(1))[0]
Out[875]: 1
I think this below should work (base on
#Mayank Porwal idea, sorry coz I can not reply):
d = {1: 5, 2: 0, 3: 4, 4: 0, 5: 1}
max(v for k,v in d.items())
Use a generator and the max builtin function:
Max value
max(v for k,v in d.items() if k in [1,2,3])
Max key
max(k for k,v in d.items() if k in [1,2,3])
I have a graph with adjacency matrix of the form below (a 6-node graph where self-edges are 0 and no_connections are marked Inf and other edges are 1):
{1: {1: 0, 2: 1, 3: inf, 4: inf, 5: inf, 6: inf}, 2: {1: 1, 2: 0, 3: inf, 4: 1, 5: 1, 6: inf}, 3: {1: inf, 2: inf, 3: 0, 4: 1, 5: inf, 6: inf}, 4: {1: inf, 2: 1, 3: 1, 4: 0, 5: 1, 6: 1}, 5: {1: inf, 2: 1, 3: inf, 4: 1, 5: 0, 6: inf}, 6: {1: inf, 2: inf, 3: inf, 4: 1, 5: inf, 6: 0}}
I want to use networkx package for its all_simple_paths function to find all simple paths from a source to a destination but when I call
nx.all_simple_paths(graph, src, dst)
it gives:
AttributeError: 'dict' object has no attribute 'is_multigraph'
I currently do not have the graph in any other format. How should I resolve this issue?
Thanks.
Your graph is currently stored as a dictionary. It's a little unfair to expect networkx to work automagically on any data structure you choose. Even if it were set up to handle a dictionary in the way you've done it, how would it know how to interpret a 0 or inf?
To use networkx commands you'll need your graph to be in the networkx Graph format.
import networkx as nx
D = {1: {1: 0, 2: 1, 3: float('inf'), 4: float('inf'), 5: float('inf'), 6: float('inf')}, 2: {1: 1, 2: 0, 3: float('inf'), 4: 1, 5: 1, 6: float('inf')}, 3: {1: float('inf'), 2: float('inf'), 3: 0, 4: 1, 5: float('inf'), 6: float('inf')}, 4: {1: float('inf'), 2: 1, 3: 1, 4: 0, 5: 1, 6: 1}, 5: {1: float('inf'), 2: 1, 3: float('inf'), 4: 1, 5: 0, 6: float('inf')}, 6: {1: float('inf'), 2: float('inf'), 3: float('inf'), 4: 1, 5: float('inf'), 6: 0}}
G=nx.Graph()
for node, neighbor_dict in D.items():
G.add_node(node)
for neighbor, val in neighbor_dict.items():
if val !=0 and val <float('inf'):
G.add_edge(node, neighbor, weight=val)
for path in nx.all_simple_paths(G,1,3):
print path
>[1, 2, 4, 3]
>[1, 2, 5, 4, 3]
I have dictionary like:
item_count_per_section = {1: 3, 2: 5, 3: 2, 4: 2}
And total count of items retrieved from this dictionary:
total_items = range(sum(item_count_per_section.values()))
Now I want to transform total_items by values of dictionary following way:
items_no_per_section = {1: [0,1,2], 2: [3,4,5,6,7], 3:[8,9], 4:[10,11] }
I.e. slice total_items sequencially to sublists which startrs from previous "iteration" index and finished with value from initial dictionary.
You don't need to find total_items at all. You can straightaway use itertools.count, itertools.islice and dictionary comprehension, like this
from itertools import count, islice
item_count_per_section, counter = {1: 3, 2: 5, 3: 2, 4: 2}, count()
print {k:list(islice(counter, v)) for k, v in item_count_per_section.items()}
Output
{1: [0, 1, 2], 2: [3, 4, 5, 6, 7], 3: [8, 9], 4: [10, 11]}
dict comprehension of itertools.isliced iter of total_items:
from itertools import islice
item_count_per_section = {1: 3, 2: 5, 3: 2, 4: 2}
total_items = range(sum(item_count_per_section.values()))
i = iter(total_items)
{key: list(islice(i, value)) for key, value in item_count_per_section.items()}
Outputs:
{1: [0, 1, 2], 2: [3, 4, 5, 6, 7], 3: [8, 9], 4: [10, 11]}
Note: this works for any total_items, not just range(sum(values)), assuming that was just your sample to keep the question generic. If you do just want the numbers, go with #thefourtheye's answer