Python items sort with only first word in an item

Viewed 77

Trying to sort by the number of identical items, from largest to smallest item count... There is an array:

[['red', 1], ['blue', 2], ['blue', 3], ['green', 4], ['red', 5], ['red', 6]]

Need output:

[['red', 1],
['red', 5],
['red', 6],
['blue', 2],
['blue', 3],
['green', 4]]

Trying with collections Counter, but i dont know how count only words... Maybe somebody can help me.

3 Answers

You could use Counter like below:

from collections import Counter

data = [['red', 1], ['blue', 2], ['blue', 3], ['green', 4], ['red', 5], ['red', 6]]
counts = Counter(e for e, _ in data)
result = sorted(data, key=lambda e: counts.get(e[0], 0), reverse=True)
print(result)

Output

[['red', 1], ['red', 5], ['red', 6], ['blue', 2], ['blue', 3], ['green', 4]]

If counts is used in the same list, you could do, as suggested by @Barmar:

result = sorted(data, key=lambda e: counts[e[0]], reverse=True)

Here is non Counter version:

lol=[['red', 1],
['red', 5],
['red', 6],
['blue', 2],
['blue', 3],
['green', 4]]

cnt={}

for color, x in lol:
    cnt[color]=cnt.get(color, 0)+x
    
print(sorted(lol, key=lambda sl: (cnt[sl[0]], sl[1]), reverse=True))

# [['red', 6], ['red', 5], ['red', 1], ['blue', 3], ['blue', 2], ['green', 4]]

Since this is creating a tuple of (total_cnt_by_color, count_for_this_element) it sorts both by group count and the individual count for each list entry. If you don't want that, remove the second element of the tuple.


If you want the number of occurrences of a color vs the sum of the values of that color, you can do:

for color, x in lol:
    cnt[color]=cnt.get(color, 0)+1

print(sorted(lol, key=lambda sl: (cnt[sl[0]], sl[1]), reverse=True))

I edited above code so that it truly works for all given cases. The problem with the provided solution above, is that it sorts based on the value of the total color items combined, rather than their occurence. If someone were to change the values of the blue items to 12 and 13, the given solution would break, cause now 12 and 13 is more than 6, 5 and 1, which would be the sorting number for red. The only change I made is that instead of adding the value for the color in the for loop, I add 1 to indicate that one more of the given item has been processed. See my solution below.

    lol=[['red', 1],
    ['red', 5],
    ['red', 6],
    ['blue', 12], #when set to these values, the previous solution 
    ['blue', 13], #would break
    ['green', 4]]

    cnt={}

    for color, x in lol:
        cnt[color]=cnt.get(color, 0)+1   # Here 1 is added

    print(sorted(lol, key=lambda sl: (cnt[sl[0]], sl[1]), reverse=True))

    # [['red', 6], ['red', 5], ['red', 1], ['blue', 13], ['blue', 12], ['green', 
    # 4]]

Good day!

Related