1 00:00:00,000 --> 00:00:04,993 [MUSIC] 2 00:00:04,993 --> 00:00:06,490 As you know, lists are mutable, 3 00:00:06,490 --> 00:00:10,001 which means that we can change them in place without having to make a new list. 4 00:00:10,001 --> 00:00:11,879 This is great most of the time. 5 00:00:11,879 --> 00:00:15,603 It makes it really easy for us to add a new value to a list, take a value out, or 6 00:00:15,603 --> 00:00:17,230 replace a value. 7 00:00:17,230 --> 00:00:21,550 This isn't great though when we need to change a list for some small action. 8 00:00:21,550 --> 00:00:25,210 Maybe we need a quick and easy way to get the first item from a list alphabetically, 9 00:00:25,210 --> 00:00:27,510 but we don't need to change the list everywhere. 10 00:00:27,510 --> 00:00:30,030 If we call sort on a list, it'll sort it in place, 11 00:00:30,030 --> 00:00:33,150 which means that the list is now sorted everywhere. 12 00:00:33,150 --> 00:00:34,650 Remember that rule about no side effects? 13 00:00:35,700 --> 00:00:39,420 Luckily, we have a couple of ways of sorting lists without changing them. 14 00:00:39,420 --> 00:00:41,750 Let's go take a look at that in WorkSpaces. 15 00:00:41,750 --> 00:00:46,740 So, one of the easiest things we can get into for avoiding side effects, 16 00:00:47,935 --> 00:00:54,275 is the idea of functions that return copies of our mutable stuff. 17 00:00:54,275 --> 00:00:57,245 So let's go back to our bad examples idea and 18 00:00:57,245 --> 00:01:02,225 we had this important_list and 19 00:01:02,225 --> 00:01:06,169 it was [5, 3, 1, 2, 4,] something like that. 20 00:01:07,610 --> 00:01:12,364 And we don't want to do important_list.sort, 21 00:01:12,364 --> 00:01:15,088 because that's a bad idea. 22 00:01:15,088 --> 00:01:18,260 That's going to sort our list in place, and we don't want that. 23 00:01:18,260 --> 00:01:19,610 You know what, I'm going to leave that there, and 24 00:01:19,610 --> 00:01:22,970 I'm gonna say, bad idea, sorts list in place. 25 00:01:22,970 --> 00:01:27,370 And then we're gonna comment that line out cuz we don't want that line to happen. 26 00:01:27,370 --> 00:01:34,080 So what do we do if we want important_list to be sorted for something, right? 27 00:01:34,080 --> 00:01:38,380 We need to print the sorted version of the list, or 28 00:01:38,380 --> 00:01:40,230 we need to use the sorted version of the list. 29 00:01:40,230 --> 00:01:43,028 Well, Python has a handy function called sorted. 30 00:01:43,028 --> 00:01:47,210 And what sorted does is it returns you a sorted copy of the list. 31 00:01:47,210 --> 00:01:49,590 It doesn't sort the original list. 32 00:01:49,590 --> 00:01:54,720 It takes the original list, makes a copy, sorts that copy, sends you back that copy. 33 00:01:54,720 --> 00:01:55,690 So let's look at this. 34 00:01:55,690 --> 00:02:00,395 Let's do print(important_list). 35 00:02:00,395 --> 00:02:03,990 Actually, we don't need to print(important_list) there. 36 00:02:05,356 --> 00:02:11,500 We can print(important_list) here after we print the sorted 37 00:02:11,500 --> 00:02:17,470 version of important_list, just to prove that the list isn't getting sorted. 38 00:02:17,470 --> 00:02:22,779 So if we do python stock.py, our sorted version here comes out as [1, 39 00:02:22,779 --> 00:02:26,080 2, 3, 4, 5], as it should. 40 00:02:26,080 --> 00:02:28,490 And we still get [5, 3, 1, 2, 4], just like that. 41 00:02:30,540 --> 00:02:36,690 So we didn't actually change sorted, so that's good. 42 00:02:36,690 --> 00:02:38,165 So I'll leave another comment here, 43 00:02:38,165 --> 00:02:44,260 sorted(important_list) Sorts a copy of the list. 44 00:02:46,500 --> 00:02:47,810 And we'll take those out. 45 00:02:47,810 --> 00:02:48,430 Okay, but 46 00:02:48,430 --> 00:02:53,510 now just using sorted on its own like that isn't the most useful thing ever. 47 00:02:53,510 --> 00:02:57,030 I mean, that's cool, I can sort a list, but what if I need to sort it about 48 00:02:57,030 --> 00:03:02,840 something that isn't just the natural state of the list, right? 49 00:03:02,840 --> 00:03:06,020 If you look here I have a list of books, right? 50 00:03:06,020 --> 00:03:07,800 Like BOOKS here is a list of books. 51 00:03:07,800 --> 00:03:12,120 But if I say sort these books, it doesn't know how to sort these books. 52 00:03:12,120 --> 00:03:15,710 It's probably gonna end up doing it by the repper, which is the title. 53 00:03:15,710 --> 00:03:17,170 So then I get them sorted by title. 54 00:03:17,170 --> 00:03:19,520 But maybe that's handy, maybe that's not. 55 00:03:20,580 --> 00:03:24,400 So let's look at a couple different ways to sort different things. 56 00:03:24,400 --> 00:03:28,520 So first of all, we need to go up here and we need to import a couple of things. 57 00:03:28,520 --> 00:03:33,730 From operator import itemgetter, and, let's see, 58 00:03:33,730 --> 00:03:38,270 I like the alphabetical things, attrgetter. 59 00:03:39,290 --> 00:03:45,760 Okay, so we're gonna import attrgetter, or attribute getter, and itemgetter. 60 00:03:45,760 --> 00:03:46,440 So what do these do? 61 00:03:46,440 --> 00:03:50,520 These are little tiny functions that you give it an object, and 62 00:03:50,520 --> 00:03:54,270 you give it a key or an attribute name, and then you say, 63 00:03:54,270 --> 00:03:59,500 hey, get me this thing from this other thing and it does that for you. 64 00:03:59,500 --> 00:04:03,080 So really handy, and it's awesome. 65 00:04:03,080 --> 00:04:11,860 So let's do RAW_BOOKS = get_books ('books.json', and we say raw=True. 66 00:04:11,860 --> 00:04:16,830 Okay, so now, I don't need this list, comment that out. 67 00:04:16,830 --> 00:04:22,900 So now I have raw books and I have books, both of which are all my book objects. 68 00:04:22,900 --> 00:04:26,290 So If I look at raw books, it's just a bunch of dictionaries. 69 00:04:26,290 --> 00:04:29,000 It's a list of dictionaries, how do I sort that? 70 00:04:29,000 --> 00:04:31,590 Well I sort that with item getter. 71 00:04:31,590 --> 00:04:33,170 So let's try this. 72 00:04:33,170 --> 00:04:38,137 Let's do, sorted(raw_data, 73 00:04:38,137 --> 00:04:42,460 key=, and so key, let's talk about key for a second. 74 00:04:42,460 --> 00:04:46,460 Key is a quarg to sorted that says, 75 00:04:46,460 --> 00:04:50,420 use this thing as the key that you're going to sort by. 76 00:04:50,420 --> 00:04:56,540 So I'm gonna sort by itemgetter, and I'm gonna sort this by 'publish_date'. 77 00:04:56,540 --> 00:04:57,410 All right. 78 00:04:57,410 --> 00:04:59,766 So we'll say this is pub_sort. 79 00:04:59,766 --> 00:05:03,098 All right. 80 00:05:03,098 --> 00:05:03,934 So. 81 00:05:03,934 --> 00:05:05,600 Oops. 82 00:05:05,600 --> 00:05:07,780 Gotta close another parentheses there. 83 00:05:07,780 --> 00:05:15,290 So I should be able to print(pub_sort[0] So ['publish_date']. 84 00:05:18,360 --> 00:05:23,630 And I should be able to print the negative one here. 85 00:05:25,090 --> 00:05:27,880 And those should be two different dates. 86 00:05:27,880 --> 00:05:28,680 So let's try that out. 87 00:05:29,780 --> 00:05:32,395 Oh, I'm sorry, I said raw_data and that should be RAW_BOOKS. 88 00:05:35,440 --> 00:05:36,200 So let's try that out. 89 00:05:38,590 --> 00:05:42,150 Yep, the first one was 1975 and the last one was 2011. 90 00:05:42,150 --> 00:05:46,810 So cool, I was able to do that through the published date 91 00:05:46,810 --> 00:05:48,340 key that each of these dictionaries had. 92 00:05:48,340 --> 00:05:52,380 All right, let's do something similar. 93 00:05:53,410 --> 00:05:56,370 You're probably wondering why is he commenting these out? 94 00:05:56,370 --> 00:05:58,420 I'm commenting them out so they'll stay here, but 95 00:05:58,420 --> 00:06:01,960 I don't want them to run cuz they're gonna take up a little bit of processing time. 96 00:06:01,960 --> 00:06:05,940 So if we don't have to use up that processing time, that's even better. 97 00:06:05,940 --> 00:06:09,140 So now let's do another sorted and let's do this one on books. 98 00:06:09,140 --> 00:06:14,930 We're going to sort the objects, the book classes that I made. 99 00:06:14,930 --> 00:06:19,470 All right, so we have books which is all of our data, and then so 100 00:06:19,470 --> 00:06:24,150 let's do that with our key is going to be attrgetter. 101 00:06:24,150 --> 00:06:29,200 We're going to pass in the ('number_of_pages') attribute. 102 00:06:30,840 --> 00:06:32,770 So, let's call that pages_sort. 103 00:06:32,770 --> 00:06:35,670 And then we can change this. 104 00:06:41,325 --> 00:06:44,741 And then let's clear and then rerun that. 105 00:06:49,285 --> 00:06:50,135 Oh, haha. 106 00:06:50,135 --> 00:06:54,545 Look at me trying to use these like they're dictionaries 107 00:06:54,545 --> 00:06:56,045 when they're actually objects. 108 00:06:57,525 --> 00:06:58,085 Silly me. 109 00:07:00,275 --> 00:07:04,942 Oh, and you know what, we should change this to be number_of_pages. 110 00:07:08,055 --> 00:07:12,185 That's what I get for just thinking I can use code exactly as it's already written. 111 00:07:12,185 --> 00:07:13,160 [LAUGH] So there we go. 112 00:07:13,160 --> 00:07:19,440 The shortest one is 245 pages and the longest one is 1,141 pages. 113 00:07:19,440 --> 00:07:24,140 So, two ways of sorting effectively the same group of stuff, 114 00:07:24,140 --> 00:07:25,550 by whatever key we want. 115 00:07:25,550 --> 00:07:30,630 So, as you've probably guessed, when we're doing itemgetter and 116 00:07:30,630 --> 00:07:32,920 attrgetter, we don't have to pass in an object. 117 00:07:32,920 --> 00:07:36,240 Sorted sends the object to that key. 118 00:07:36,240 --> 00:07:38,310 So that's pretty cool. 119 00:07:38,310 --> 00:07:39,650 Pretty handy. 120 00:07:39,650 --> 00:07:44,645 One other thing that we can talk about real quick is we can do 121 00:07:44,645 --> 00:07:49,370 reverse=True and 122 00:07:49,370 --> 00:07:54,180 it'll flip our objects around, which is handy. 123 00:07:54,180 --> 00:07:57,400 I know that was a lot to cover, congratulations on making it through. 124 00:07:57,400 --> 00:08:00,358 Learning to use sorted, reversed, and the two getter functions, 125 00:08:00,358 --> 00:08:03,440 itemgetter and attrgetter, really simplifies ordering lists. 126 00:08:04,440 --> 00:08:07,895 In the next video we'll look at map, a handy way to transform iterables.