2

So for example

['John','John','Mike','Mike','Kate','Kate']

Should return:

[('John', 2), ('Kate', 2), ('Mike', 2)]

How can I write code so there is order instead of those three pairs just being in random order?

I need to sort the list of tuples by count from biggest to smallest unless there are ties, then I need to sort the times alphabetically.

3 Answers3

1

This works:

>>> names = ['John','John','Mike','Mike','Kate','Kate']
>>> sorted(Counter(names).items(), key=lambda item: (-item[1], item[0]))
[('John', 2), ('Kate', 2), ('Mike', 2)]

The counter's items will give you tuples of (name, count). Normally you'd use Counter.most_common to get the items in order of their counts, but as far as I can tell, it only sorts by count and disregards any key (name) information in the sorting.

Since we have to re-sort again anyway, we might as well use sorted on the items instead. Since tuples sort lexicographically, and you want to sort primarily by the count, the key function should return a tuple of the format (count, name). However, since you want this to be decreasing by count, but increasing by name, the only thing we can do is return a tuple of the format (-count, name). This way, larger count will result in a lower value so it will sort before values with lower counts.

mgilson
  • 300,191
  • 65
  • 633
  • 696
  • Sorry. I'm not sure if I follow you. I'm new to Python...I don't want to just use this code and not understand it. I need to sort the list of tuples by count from biggest to smallest unless there are ties, then I need to sort the times alphabetically. – Random Stuff Sep 14 '16 at 05:33
  • it should be `sorted(Counter(names).items(), key=lambda item: item[::-1])` and for input: `names = ['John','John','Mike','Mike','Kate','Kate','ADF','ABCD','ACD','DF','BC']` I got output as `[('ABCD', 1), ('ACD', 1), ('ADF', 1), ('BC', 1), ('DF', 1), ('John', 2), ('Kate', 2), ('Mike', 2)]` Is this correct output @Random Stuff? – Kalpesh Dusane Sep 14 '16 at 05:44
  • The ones with the biggest count should be in the front, but other than that yes. Can you explain to me how this works? – Random Stuff Sep 14 '16 at 05:47
  • @RandomStuff -- I've done my best to illuminate the key points in the text. Is there any specific part that you're not following? – mgilson Sep 14 '16 at 06:04
  • I am following it, but I'm actually new to Counter(), key, lambda, and using items() in this case. It would be also impossible for me to think of this alone...I am looking everything up right now, but if you can explain those terms, that'd be great!!!!!! – Random Stuff Sep 14 '16 at 06:08
  • Ok, so first `Counter` takes a sequence as input and returns a dictionary: `Counter(['foo', 'foo', 'bar'])` -> `{'foo': 2, 'bar': 1}`. `.items()` on a dictionary takes the key/value pairs and returns them: `{'foo': 2, 'bar': 1}.items() -> [('foo', 2), ('bar', 1)]`. As for sorting by a key function, that is really well described [elsewhere](https://docs.python.org/2/howto/sorting.html)... – mgilson Sep 14 '16 at 06:14
  • Ahhhhhhhhh ok. I kinda get it I think. I'll look through more examples. Thanks :) I'm currently watching this video ;D https://www.youtube.com/watch?v=u3Pe0zizqKk...Wait so I use lambda to pass one function to another? Why can't I just use that original function? – Random Stuff Sep 14 '16 at 06:18
  • `func = lambda x: x.foo` is basically the same thing as `def func(x): return x.foo`. – mgilson Sep 14 '16 at 06:49
  • ooooooooooo I see. Is there a way to do this problem with JUST for loops and if statements? Like if I don't know any of this? – Random Stuff Sep 15 '16 at 00:04
1

You can sort your result using sorted() function using the key argument to define how to sort the items:

result = [('John', 2), ('Kate', 2), ('Mike', 3)]
sorted_result = sorted(result, key=lambda x: (-x[1], x[0]))

As you want to sort the result in descending order on the count value and then the name in ascending order, so the key (-x[1], x[0]) will do the trick.

The sorted_result will be:

[('Mike', 3), ('John', 2), ('Kate', 2)]
acw1668
  • 40,144
  • 5
  • 22
  • 34
  • Thanks! I did result.sort(key=lambda x: (-x[1], x[0]) and it works....but can you thoroughly explain how this works? I don't exactly know what key or lambda do...Also, does the negative sign before the x[1] make it go the other order? – Random Stuff Sep 14 '16 at 06:04
  • `key` is the named argument for `sorted` function, details can be refer to https://docs.python.org/3/library/functions.html#sorted. `lambda` is used to define nameless function in-place. The first `-x[1]` in `(-x[1], x[0])` will sort the original `count` part in reverse order. The second `x[0]` will be used to sort the original `name` part in ascending order if the `count` part is the same. – acw1668 Sep 14 '16 at 06:22
  • Ahhh kk. Is there a way to do this without using any of this? With just for loops and if statements? – Random Stuff Sep 14 '16 at 23:58
0

There are two ways to do this. In the first method, a sorted list is returned. In the second method, the list is sorted in-place.

import operator

# Method 1
a = [('Mike', 2), ('John', 2), ('Kate', 2), ('Arvind', 5)]
print(sorted(a, key = lambda x : (x[0],)))

# Method 2
a = [('Mike', 2), ('John', 2), ('Kate', 2), ('Arvind', 5)]
a.sort(key=operator.itemgetter(0))
print(a)
coder.in.me
  • 1,048
  • 9
  • 19
  • Hi. I need to sort the list of tuples by count from biggest to smallest unless there are ties, then I need to sort the times alphabetically. How can I do this in addition to the string value? – Random Stuff Sep 14 '16 at 05:58