Reputation: 103
I have a nested list with various names that appear more than once. I need to write a function that counts how many times each name appears and then appends it into a list that shows the name and then the count number for it. For example, the input may look like:
L = [['Jimmy', 'Henry'], ['Henry', 'Bob'], ['Lucas', 'Jimmy']]
and I would want the output to be a list like this:
newList = [['Jimmy', 2], ['Henry', 2], ['Bob', 1], ['Lucas', 1]]
I have written the following function:
def nameCount(target):
count = 0
name = target
for subList in L:
if name in subList:
count += 1
print(count)
However this only produces the number count for one name which I have to assign as the target. I would like it to go through each name and count how many times it is there and then appends it to the new list.
Upvotes: 3
Views: 202
Reputation: 334
Why don't you use a dict? I would do it like this:
def names_count(L):
result = {}
for subList in L:
for name in subList:
if name not in dict:
result[name] = 0
result[name] = result[name] + 1
return(result)
If you must do it with a result list than you can use this litle workaround:
def get_index_of_list_with(list, name):
for i in len(list): # I normally prefered enumerate here but you didn't want anything but pure iteration, right?
if list[i] is name:
return i
list.append[name, 0]
return len(list) - 1
def nameCount(L):
result = []
for subList in L:
for name in subList:
index = get_index_of_list_with(result, name)
result[index] = result[index] + 1
print(result)
Note that the second solution is not pythonic at all and that there is probobly a better way to code the first example too. They ar just drafts.
Upvotes: 0
Reputation: 556
import collections
import itertools
L = [['Jimmy', 'Henry'], ['Henry', 'Bob'], ['Lucas', 'Jimmy']]
[list(i) for i in collections.Counter(itertools.chain(*L)).items()]
---> [['Bob', 1], ['Lucas', 1], ['Jimmy', 2], ['Henry', 2]]
Upvotes: 3
Reputation: 78554
Use collections.Counter
:
from collections import Counter
print Counter(i for x in L for i in x).most_common()
# [('Jimmy', 2), ('Henry', 2), ('Bob', 1), ('Lucas', 1)]
You can also use a vanilla dict with a for loop :
d = {}
for x, y in L:
d[x] = d.get(x, 0) + 1
d[y] = d.get(y, 0) + 1
print d.items()
# [('Jimmy', 2), ('Henry', 2), ('Bob', 1), ('Lucas', 1)]
Upvotes: 3
Reputation: 52223
You can use collections.Counter
:
>>> collections.Counter(itertools.chain(*L))
Counter({'Bob': 1, 'Henry': 2, 'Jimmy': 2, 'Lucas': 1})
>>> collections.Counter(itertools.chain(*L)).items()
[('Bob', 1), ('Jimmy', 2), ('Lucas', 1), ('Henry', 2)]
Without using any builtin function, you can do:
result = {}
for subList in L:
for name in subList:
result[name] = result.get(name, 0) + 1
print(result.items())
Upvotes: 1
Reputation: 438
If you'd like to use numpy, the following will return tuples:
import numpy as np
L = [['Jimmy', 'Henry'], ['Henry', 'Bob'], ['Lucas', 'Jimmy']]
name, count = np.unique(L, return_counts=True)
zip(name, count)
The following will also return a dictionary:
dict(zip(name,count))
Upvotes: 0
Reputation: 54303
If you only want to use basic objects:
L = [['Jimmy', 'Henry'], ['Henry', 'Bob'], ['Lucas', 'Jimmy']]
def nameCount(nested_names):
count = {}
for sub_list in nested_names:
for name in sub_list:
count[name] = count.get(name, 0) + 1
print(count)
nameCount(L)
It outputs:
{'Bob': 1, 'Jimmy': 2, 'Lucas': 1, 'Henry': 2}
If you want sorted tuples:
print(sorted(count.items(), key=lambda x: x[1], reverse=True))
which outputs:
# [('Jimmy', 2), ('Henry', 2), ('Bob', 1), ('Lucas', 1)]
Upvotes: 0
Reputation: 15204
If you do not want to import anything you can just do this:
L = [['Jimmy', 'Henry'], ['Henry', 'Bob'], ['Lucas', 'Jimmy']]
temp = [x for y in L for x in y] # flattens L
new_list = [[k, temp.count(k)] for k in set(temp)]
print(new_list) # [['Henry', 2], ['Lucas', 1], ['Bob', 1], ['Jimmy', 2]]
note that it does not preserve order since it involves the creation of a set. The creation of temp
is not needed but does speed things up. It is used to flatten the original list which is initially nested.
Upvotes: 1