# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

from collections import namedtuple

# ## Problem
# - you want to sort a list of comments represented as tuples, namedtuples, dicts, objects by either the number of likes or comment.content length.

# +
comment_str = 'Python3 is awesome'

comment_tuple = ('Junior', 'Python3 is awesome', 5, (8, 5, 2019))

comment_dict = dict(author='Junior', content='Python3 is awesome', likes=5, date=(8, 5, 2019))

Comment = namedtuple('Comment', ['author', 'content', 'likes', 'date'])
comment_ntuple = Comment('Junior', 'Python3 is awesome', 10, (9, 5, 2019))
# -

# ## Answer
# - we can use the key argument of the sorted function or .sort method to provide a custom sorting value.

# +
# Example 1: sorting str_comments by their length
str_comments = ['Python3 is awesome', 'Yeah!!', 'I prefer Python3 over Python2', 'Absolutely!']

print(sorted(str_comments)) #<0> By default sorted by lexicographic order
# -

print(sorted(str_comments, key=len)) #<1>

print(sorted(str_comments, key=len, reverse=True)) 



# +
# Example 2: sorting tuple_comments by their number of likes
tuple_comments = [
    ('Junior', 'Python3 is awesome', 5, (8, 5, 2019)),
    ('Amy', 'Yeah!!', 2, (8, 5, 2019)),
    ('Paul', 'I prefer Python3 over Python2', 10, (8, 5, 2019)),
    ('Zak', 'Absolutely!', 0, (8, 5, 2019)),
    ('Amy', 'Anyone still using Python2? LOL', 15, (8, 5, 2019)),

]
# -

sorted(tuple_comments) #<2>

from operator import itemgetter
sorted(tuple_comments, key=itemgetter(2), reverse=True) #<3>  key=lambda comment: comment[2]



# Example 3: sorting dict_comments by their number of likes
dict_comments = [
    dict(author='Junior', content='Python3 is awesome', likes=5, date=(8, 5, 2019)),
    dict(author='Amy', content='Yeah!!', likes=2, date=(8, 5, 2019)),
    dict(author='Paul', content='I prefer Python3 over Python2', likes=10, date=(8, 5, 2019)),
    dict(author='Zak', content='Absolutely', likes=0, date=(8, 5, 2019)),
]

sorted(dict_comments, key=itemgetter('likes'), reverse=True)  #<4>  key=lambda comment: comment['likes']

# +
# Example 4: sorting named_tuple_comments by their number of likes
Comment = namedtuple('Comment', ['author', 'content', 'likes', 'date'])


named_tuple_comments = [
    Comment('Junior', 'Python3 is awesome', 5, (8, 5, 2019)),
    Comment('Amy', 'Yeah!!', 2, (8, 5, 2019)),
    Comment('Paul', 'I prefer Python3 over Python2', 10, (8, 5, 2019)),
    Comment('Zak', 'Absolutely!', 0, (8, 5, 2019))
]
# -

from operator import attrgetter
sorted(named_tuple_comments, key=attrgetter('likes'), reverse=True)  #<5> key=lambda comment: comment.likes



# Example 5: sorting named_tuple_comments by their contents legnth
sorted(named_tuple_comments, key=lambda comment: len(comment.content), reverse=True) #<6>



# ## Discussion
# - <0> By the default, list of str are sorted in lexicographic order, but that's not what we want.
# - <1> We provide a key function which will be applied to each element in the sequence and the returned value would be used for sorting.
# - <2> By default, list of tuples are sorted according to the order by which their inner elements would have been sorted from left to right. 
# - <3> itemgetter enables us to sort by the number of likes only, which is at position 2 in the comment_tuple hence itemgetter(2)
# - <4> itemgetter also works with list of dicts, hence itemgetter('likes')
# - <5> For nametuples we can use itemgetter still (everything tuple can, namedtuple can :) ) but even better we can also use attrgetter('likes') which also works for custom defined objects.
# - <6> lambda function passed to the key argument to sort by the length of the comment.content



StarcoderdataJupyterScriptsDedupFiltered