i have used list comprehensions not very often but i was wondering if the below lines can be a one liner (yes the code is already small, but i am curious):
lst = ['hi', 'hello', 'bob', 'hello', 'bob', 'hello']
for index in lst:
data[index] = data.get(index,0) + 1
data would be: {'hi':1, 'hello':3, 'bob':2}
something:
d = { ... for index in lst } ????
I have tried some comprehensions but they don't work:
d = { index:key for index in lst if index in d: key = key + 1 else key = 1 }
Thanks in adv.
Simply use collections.Counter
A Counter is a dict subclass for counting hashable objects. It is an
unordered 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.
import collections
l = ['hi', 'hello', 'bob', 'hello', 'bob', 'hello']
c = collections.Counter(l)
assert c['hello'] == 3
Related
I have a list
list_1 = ['warning', 'media', 'media-other','media-other','warning-type2','threat','threat-type1]
I need to count the occurrence of different types as in the following dictionary
dict_1 = {'warning':0, 'media':0, 'threat':0}
I need to select similar types and increase the count. media and media-other should be counted as media. warning and warning-type2 should be counted as warning
The output of dict_1 after counting should be {'warning':2, 'media':3, 'threat':2}
list_1 = ['warning', 'media', 'media-other','media-other','warning-type2','threat','threat-type1']
list_2 = [x.split('-')[0] for x in list_1]
dict_1 = {}
for key in list_2:
if key not in dict_1.keys():
dict_1[key] = list_2.count(key)
print(dict_1)
Assuming the part before any hyphen gives you the 'type' of the items in the list, you can use split and collections.Counter to count them:
from collections import Counter
Counter(word.split("-")[0] for word in list_1)
# returns Counter({'warning': 2, 'media': 3, 'threat': 2})
I've been working on a solution for an assignment where we which accepts a list of tuple objects and returns a dictionary containing the frequency of all the strings that appear in the list
So I've been trying to use Counter from collections to count the frequency of a key that is occurring inside a tuple list
tuple_list = [('a',5), ('a',5), ('b',6), ('b',4), ('b',3), ('b',7)]
I can't get the Counter to only check for 'a' or 'b' or just the strings in the list.
from collections import Counter
def get_frequency(tuple_list):
C = Counter(new_list)
print (C('a'), C('b'))
tuple_list = [('a',5), ('a',5), ('b',6), ('b',4), ('b',3), ('b',7)]
freq_dict = get_frequency(tuple_list)
for key in sorted(freq_dict.keys()):
print("{}: {}".format(key, freq_dict[key]))
The output that I was expecting should be a: 2 b: 4 but I kept on getting a: 0 b: 0
Since the second (numeric) element in each tuple appears to be irrelevant, you need to pass in a sequence of the letters you're trying to count. Try a list comprehension:
>>> tuple_list = [('a',5), ('a',5), ('b',6), ('b',4), ('b',3), ('b',7)]
>>>
>>> items = [item[0] for item in tuple_list]
>>> items
['a', 'a', 'b', 'b', 'b', 'b']
>>> from collections import Counter
>>> c = Counter(items)
>>> print(c)
Counter({'b': 4, 'a': 2})
if you don't want to use counter, you can just do the length of the lists like this...
unique_values = list(set([x[0] for x in tuple_list]))
a_dict = {}
for v in unique_values:
a_dict[v] = len([x[1] for x in tuple_list if x[0] == v])
print(a_dict)
which gives you:
{'b': 4, 'a': 2}
Since you only want to count the first element (the string) in each tuple, you should only use the counter object on that first element as you can see in the get_frequency function below:
def get_frequency(tuple_list):
cnt = Counter()
for tuple_elem in tuple_list:
cnt[tuple_elem[0]] += 1
return cnt
tuple_list = [('a',5), ('a',5), ('b',6)]
freq_dict = get_frequency(tuple_list)
for key, value in freq_dict.items():
print(f'{key}: {value}')
Also, make sure if you hope to receive a value from a function, you usually need to return a value using a return statement.
Hope that helps out!
Another solution is to use zip and next to extract the first item of each tuple into a new tuple and feed it into Counter.
from collections import Counter
result = Counter(next(zip(*items)))
I have a dictionary contains lists of values and a list:
dict1={'first':['hi','nice'], 'second':['night','moon']}
list1= [ 'nice','moon','hi']
I want to compare the value in the dictionary with the list1 and make a counter for the keys if the value of each key appeared in the list:
the output should like this:
first 2
second 1
here is my code:
count = 0
for list_item in list1:
for dict_v in dict1.values():
if list_item.split() == dict_v:
count+= 1
print(dict.keys,count)
any help? Thanks in advance
I would make a set out of list1 for the O(1) lookup time and access to the intersection method. Then employ a dict comprehension.
>>> dict1={'first':['hi','nice'], 'second':['night','moon']}
>>> list1= [ 'nice','moon','hi']
>>>
>>> set1 = set(list1)
>>> {k:len(set1.intersection(v)) for k, v in dict1.items()}
{'first': 2, 'second': 1}
intersection accepts any iterable argument, so creating sets from the values of dict1 is not necessary.
You can use the following dict comprehension:
{k: sum(1 for i in l if i in list1) for k, l in dict1.items()}
Given your sample input, this returns:
{'first': 2, 'second': 1}
You can get the intersection of your list and the values of dict1 using sets:
for key in dict1.keys():
count = len(set(dict1[key]) & set(list1))
print("{0}: {1}".format(key,count))
While brevity can be great, I thought it would be good to also provide an example that is as close to the OPs original code as possible:
# notice conversion to set for O(1) lookup
# instead of O(n) lookup where n is the size of the list of desired items
dict1={'first':['hi','nice'], 'second':['night','moon']}
set1= set([ 'nice','moon','hi'])
for key, values in dict1.items():
counter = 0
for val in values:
if val in set1:
counter += 1
print key, counter
Using collections.Counter
from collections import Counter
c = Counter(k for k in dict1 for i in list1 if i in dict1[k])
# Counter({'first': 2, 'second': 1})
The most simplest and basic approach would be:
dict1={'first':['hi','nice'], 'second':['night','moon']}
list1= [ 'nice','moon','hi']
listkeys=list(dict1.keys())
listvalues=list(dict1.values())
for i in range(0,len(listvalues)):
ctr=0
for j in range(0,len(listvalues[i])):
for k in range(0,len(list1)):
if list1[k]==listvalues[i][j]:
ctr+=1
print(listkeys[i],ctr)
Hope it helps.
This question already has answers here:
Create a dictionary with comprehension
(17 answers)
Closed 5 years ago.
I am looking for a short and compact one-liner to initialize a dictionary from a list in Python. Is there an equivalent to the two constructs below?
dic = {}
for elt in list:
dic[elt.hash] = elt
.
dic2 = {}
defaultValue = 0
for elt in list:
dic2[elt] = defaultValue
I've see the use of Counter for the second case, but it is a very narrow case, and I'm looking for a generic syntax.
Summary of three pythonic solutions to instantiating dictionaries. Having a "one-line" solution should never be the most important consideration.
1. Keys and default value defined in advance.
Instead of setting a default value for every key, use dict.fromkeys. Also, do not name variables the same as classes, e.g. use lst instead.
dic2 = dict.fromkeys(lst, 0)
2. Default value defined in advance, but not keys.
Alternatively, if you will be adding more keys in the future, consider using collections.defaultdict, which is a subclass of dict:
from collections import defaultdict
dic2 = defaultdict(int)
dic2['newkey'] # returns 0 even not explicitly set
3. Keys and values related by a function.
For building a dictionary where keys and values are linked via a function, use a dictionary comprehension, as described in detail by #OmerB, e.g.
{k: f(k) for k in lst} # value function of given keys
{f(v): v for v in lst} # key function of given values
Well, dictionary comprehension is one-line, is that what you mean?
>> MyList = ['apple', 'banana', 'pear']
>> {hash(element): element for element in MyList}
{-8723846192743330971: 'pear',
-6060554681585566095: 'banana',
-4133088065282473265: 'apple'}
Also - I'm suspecting that using the element's hash as the key is not what you're looking for:
If your elements are immutable (e.g. strings), you could use the elements themselves as keys.
If they're not immutable, you can use the element's location in the list.
For the latter, to make sure you insert each value only once to the dict, clear duplicates from the list before iterating over it:
>> MyList = ['apple', 'apple', 'banana', 'banana', 'pear']
>> {idx: value for (idx,value) in enumerate(set(MyList))}
{0: 'banana', 1: 'pear', 2: 'apple'}
A simple one liner statement for case-01 using dict constructor, map and zip:
>>> l = ['a','b','c']
>>> dict(zip(map(hash,l),l))
>>> {12416037344: 'a', 12672038114: 'c', 12544037731: 'b'}
For second situation:
>>> l = ['a','b','c']
>>> default_value = 10
>>> dict((zip(l,[default_value]*len(l))))
>>> {'a': 10, 'c': 10, 'b': 10}
Those two constructs can be built using dictionary comprehensions like:
Code:
dic_comp = {getattr(elt, 'hash'): elt for elt in test_data}
dic2_comp = {elt: defaultValue for elt in test_data}
Test Code:
class TestObj(object):
def __init__(self, hash_value):
self.hash = hash_value
test_data = [TestObj(i) for i in range(5)]
dic = {}
for elt in test_data:
dic[elt.hash] = elt
dic_comp = {getattr(elt, 'hash'): elt for elt in test_data}
assert dic == dic_comp
dic2 = {}
defaultValue = 0
for elt in test_data:
dic2[elt] = defaultValue
dic2_comp = {elt: defaultValue for elt in test_data}
assert dic2 == dic2_comp
I have a list of strings like this:
l = ['ABC, Apple, 20021015, 20030102', 'CDE, Graps, 20020506, 20030130']
I want to convert this list to a dictionary like
d = { 'ABC': 'Apple', 'CDE': 'Graps' }
So the key would be the first name in the string and the value would be the second name in the string.
This works in Python 2:
d = {j[0]:j[1] for j in [i.split(', ') for i in l]}
Output:
{'CDE': 'Graps', 'ABC': 'Apple'}
You could do it like this:
for index in range(len(l)):
line = l[index].split(", ")
d[line[0]] = line[1]
So, you split each entry by commas to get each name and date individually, and then you can add them each to the dict as normal.
Alternative, shorter form:
>>> dict(x.split(', ')[:2] for x in l)
{'ABC': 'Apple', 'CDE': 'Graps'}
This works by passing a sequence of two-element lists to dict() which then initializes the dictionary based on that sequence. The sequence being passed is this:
>>> [x.split(', ')[:2] for x in l]
[['ABC', 'Apple'], ['CDE', 'Graps']]