I wanted to create an mapping between two arrays. But in python, doing this resulted in a mapping with last element getting picked.
array_1 = [0,0,0,1,2,3]
array_2 = [4,4,5,6,8,7]
mapping = dict(zip(array_1, array_2))
print(mapping)
The mapping resulted in {0: 5, 1: 6, 2: 8, 3: 7}
How to pick the most occurring element in this case 4 for key 0.
You can create a dictionary with key and a list of values for the key. Then you can go over the list of values in this dictionary, and update the value to be the most frequent item in the list using Counter.most_common
from collections import defaultdict, Counter
array_1 = [0,0,0,1,2,3]
array_2 = [4,4,5,6,8,7]
mapping = defaultdict(list)
#Create the mapping with a list of values
for key, value in zip(array_1, array_2):
mapping[key].append(value)
print(mapping)
#defaultdict(<class 'list'>, {0: [4, 4, 5], 1: [6], 2: [8], 3: [7]})
res = defaultdict(int)
#Iterate over mapping and chose the most frequent element in the list, and make it the value
for key, value in mapping.items():
#The most frequent element will be the first element of Counter.most_common
res[key] = Counter(value).most_common(1)[0][0]
print(dict(res))
The output will be
{0: 4, 1: 6, 2: 8, 3: 7}
You can count frequencies of all mappings using Counter and then sort those mappings by key and frequency:
from collections import Counter
array_1 = [0,0,0,1,2,3]
array_2 = [4,4,5,6,8,7]
c = Counter(zip(array_1, array_2))
dict(i for i, _ in sorted(c.items(), key=lambda x: (x[0], x[1]), reverse=True))
# {3: 7, 2: 8, 1: 6, 0: 4}
Related
I tried to add the string elements to the dictionary but it doesnt work
adatok = ["marha", 1, "kacsa", 2, "kacsa", 1, "birka", 3, "marha", 4, "marha", 2]
sorszámok = list(set([x for x in adatok if type(x) == int]))
szótár = {}
for i in sorszámok:#Létrehozzuk a sorszámokat egy szótárba
szótár.update({i:set()})
for j in adatok:
if type(j) == int:
szótár[j].add(adatok[adatok.index(j)-1])
#Expected output:{1: {'marha','kacsa'}, 2: {'kacsa','marha'}, 3: {'birka'}, 4: {'marha'}}
#Output:{1: {'marha'}, 2: {'kacsa'}, 3: {'birka'}, 4: {'marha'}}
Instead of starting with unique keys and then trying to find the values for each key, iterate over the key, value pairs and add them to the sets. Using defaultdict saves you the trouble of setting up the dict ahead of time.
>>> from collections import defaultdict
>>> adatok = ["marha", 1, "kacsa", 2, "kacsa", 1, "birka", 3, "marha", 4, "marha", 2]
>>> szótár = defaultdict(set)
>>> for k, v in zip(adatok[1::2], adatok[0::2]):
... szótár[k].add(v)
...
>>> dict(szótár)
{1: {'marha', 'kacsa'}, 2: {'marha', 'kacsa'}, 3: {'birka'}, 4: {'marha'}}
counts = defaultdict(int)
for elem in sets: #list of sets
for _ in elem: #each set contains elements that may be duplicates among the sets
counts[_] += 1
Is there a way to use dict comprehension for code like this?
Don't use a list comprehension for side effects (i.e. updating counts).
Instead, if you replace defaultdict(int) with Counter, you can write the solution in one line. (I assume your end goal is to make your code shorter/cleaner.)
sets = [
{1, 2, 3},
{1, 2},
{3},
{3}]
# ---
from collections import Counter
counts = Counter(x for s in sets for x in s)
print(counts) # -> Counter({3: 3, 1: 2, 2: 2})
Note: Instead of the nested generator expression, you might prefer to use itertools.chain.from_iterable(sets).
If you are adamant at using list comprehension, you can do this way:
>>> counts = {1:4, 2:5, 3:8, 4:2, 5:9}
>>> sets = [{2,3}, {3,1}, {2}]
>>> [[counts.update({e: counts[e]+1}) for e in si] for si in sets]
[[None, None], [None, None], [None]]
>>> counts
{1: 5, 2: 7, 3: 10, 4: 2, 5: 9}
But yes, as others suggested, you can do it using Counter:
#1: use Counter to get new counts from sets
#2: merge both new & default counters
#3: get Counter back into your dictionary
With sample input:
>>> counts = {1:4, 2:5, 3:8, 4:2, 5:9}
>>> sets = [{2,3}, {3,1}, {2}]
>>> from collections import Counter
>>> cntr_new = Counter(x for s in sets for x in s)
>>> cntr_new
Counter({2: 2, 3: 2, 1: 1})
>>> cntr_orig = Counter(counts)
>>> cntr_final = cntr_orig + cntr_new
Final result:
>>> dict(cntr_final)
{1: 5, 2: 7, 3: 10, 4: 2, 5: 9}
I have the following list:
lst= (1,(1,2), 3, (3,4), 1, 3)
and I want to use the dictionary function generate output that will count the number of times each value occurs such that it would look like this:
{1:3, 2:1, 3:3, 4:1}
I am lost on how to do this.
Thank you!
Below is my attempt:
def f(*args):
for x in args:
d = {x:args.count(x) for x in args}
return d
For arbitrary depth tuples, you could use a recursive function for flattening:
def flatten_nested_tuples(tuples):
for tup in tuples:
if isinstance(tup, tuple):
yield from flatten_nested_tuples(tup)
else:
yield tup
The yield from x syntax is equivalent to the for item in x: yield item. Its just a shorter way to create generators. You can have a look at this answer and this answer for more information about generators and the yield keyword.
To count we can use collections.Counter to count the flattened tuples:
from collections import Counter
lst= (1,(1,2), 3, (3,4), 1, 3)
print(Counter(flatten_nested_tuples(lst)))
Output:
Counter({1: 3, 3: 3, 2: 1, 4: 1})
Note: Counter is a subclass of dict, so you can treat it like a regular dict.
If you want to count yourself without any modules, you have to do the 0 initializing yourself:
counts = {}
for item in flatten_nested_tuples(lst):
counts[item] = counts.get(item, 0) + 1
print(counts)
# {1: 3, 2: 1, 3: 3, 4: 1}
Or without using dict.get():
counts = {}
for item in flatten_nested_tuples(lst):
if item not in counts:
counts[item] = 0
counts[item] += 1
print(counts)
# {1: 3, 2: 1, 3: 3, 4: 1}
I am trying to write a function that takes a list of strings and returns a dictionary where the keys represent a length and the values represent how many strings have that length in the list. This is what I have written and my output:
def length_counts(stringList):
stringDict = {}
for value in stringList:
stringDict[len(value)] = stringList.count(value)
return stringDict
#test
sa_countries = ["Brazil", "Venezuela", "Argentina", "Ecuador", "Bolivia", "Peru"]
print(length_counts(sa_countries))
Output:
{6: 1, 9: 1, 7: 1, 4: 1}
Correct output should be:
{6: 1, 9: 2, 7: 2, 4: 1}
Which says there is 1 string with 6 letters, 2 strings with 9 letters, 2 strings with 7 letters, and 1 string with 4 letters.
count will give you the number of occurences of that particular element. So the count of Venezuela will give you the number of Venezuela in the list, not the number of 9 letter words. Try something like this.
sa_countries = ["Brazil", "Venezuela", "Argentina", "Ecuador", "Bolivia", "Peru"]
dict = {}
for country in sa_countries:
if (len(country) in dict):
dict[len(country)] += 1
else:
dict[len(country)] = 1
print(dict)
You can use collections.defaultdict to accumulate string length counts.
from collections import defaultdict
def length_counts(countries):
result = defaultdict(int)
for country in countries:
result[len(country)] += 1
return result
Example
>>> length_counts(sa_countries)
defaultdict(<class 'int'>, {6: 1, 9: 2, 7: 2, 4: 1})
You are rewriting your values.
First you do you stringList.count('Venezuela') which is 1. Then you do stringList.count('Argentina') which is also 1. So you get value 1 for they key of 9, twice.
What I would do is first convert the initial list into a list containing the lengths.
sa_countries = ["Brazil", "Venezuela", "Argentina", "Ecuador", "Bolivia", "Peru"]
sa_countries_lens = [len(s) for s in sa_countries]
That is [6, 9, 9, 7, 7, 4].
Now I would do a count:
from collections import Counter
Counter(sa_countries_lens)
The result is
Counter({6: 1, 9: 2, 7: 2, 4: 1})
Counter is basically a dict and you can do a dict with an increment and a key check, but Counter is nicer, part of the standard library and pretty widespread.
One possible approach is to use collections.Counter; counting is what Counter is for:
from collections import Counter
sa_countries = ["Brazil", "Venezuela", "Argentina", "Ecuador", "Bolivia", "Peru"]
result = Counter(map(len, sa_countries))
print(result)
Output
Counter({9: 2, 7: 2, 6: 1, 4: 1})
From the documentation:
A Counter is a dict subclass for counting hashable objects. It is a
collection where elements are stored as dictionary keys and their
counts are stored as dictionary values. Counts are allowed to be any
integer value including zero or negative counts. The Counter class is
similar to bags or multisets in other languages.
I need to unite two lists in Python3,where duplicates can exist,and for one set of these the resulting list will contain as many as max in both lists.An example might clarify it:
[1,2,2,5]( some operator)[2,5,5,5,9]=[1,2,2,5,5,5,9]
Ideas?
You can use the collections.Counter class:
>>> from collections import Counter
>>> combined = Counter([1,2,2,5]) | Counter([2,5,5,5,9])
>>> list(combined.elements())
[1, 2, 2, 5, 5, 5, 9]
It functions as a multiset (an unordered collection where each element can appear multiple times). The | operator gives you the union of the multisets, where each element appears max(apperances_in_counter1, appearances_in_counter2) times.
This class was added in Python 2.7 and 3.1.
Why use lists in the first place? That data looks like a dict to me:
[1,2,2,5] -> {1: 1, 2: 2, 5: 1}
[2,5,5,5,9] -> {2: 1, 5: 3, 9: 1}
Then it's simple:
keys = set(a.keys()+b.keys())
vals = [max(a.get(n, 0), b.get(n, 0)) for n in keys]
d = dict(zip(keys, vals))
print d
Result:
{1: 1, 2: 2, 5: 3, 9: 1}
Convert arrays to dictionaries with a[key] = count
Create new dictionary with rules c[key] = a.get(key, 0) > b.get(key, 0) and a[key] or b[key]. You need to iterate through both keys in a and in b dicts.
Expand dictionary, result += [value] * key