Andy Van Slaars: 0:00 I have this unimplemented function called dropHighLow. My goal is to get this test to pass, and I want to be able to take an input array, and dropHighLow should give me a new array that drops the highest and the lowest values from the source array.
0:16 As we can see right now, this test is failing, because it expects this array and it's receiving undefined because there's no implementation. Let's use some utility functions from Ramda to make this function work.
0:28 I've already installed Ramda as a dependency, so I'm going to import the utility function from Ramda, and the first function we're going to import is called without. We're going to return the result of calling without.
0:46 Without takes two arguments. The first one is an array of values that we want to exclude. In this case, we know to pass this test, we want to drop 1 and 8 from the numbers array. It takes an array of values to exclude and an array to exclude those values from, and it returns a new array.
1:10 If we look back at our test, we'll see that our test is passing, because we're getting the expected array. Obviously, hard-coding these values in our function isn't going to make them very flexible, so let's see how we can calculate those values so that this'll work with any input array.
1:26 What we need to do is get the highest and lowest values out of our numbers array. To do that, I'm going to pull a couple more utilities in from Ramda. I'm going to pull in the min and max utilities, and I'm also going to pull in reduce.
1:41 Both min and max take in two values, so 1 and 2, and they return the minimum or the maximum value, depending on which function you're using. In this case, I would get 1, and if I changed this to 8, I would get the 2. If I did this with max, I'll get the higher of the two numbers.
2:06 We need to do this on an array, so we need to be able to compare more than two values. We need to compare every value in the array. To do that, we're going to combine min and max with reduce.
2:17 I'm going to reduce and I'm going to use min as my reduction function. Then I want to pass it an initial value. I want to make sure that my initial value is never going to win out over a value that's actually in my array.
2:32 To make sure that happens, I'm going to use number.maxValue as my initial value, and then I'm going to pass these numbers.
2:45 If we inspect that, we'll see that our minimum value from the array is 1. I'm going to duplicate this and I'm going to replace min with max. Here, I want to use the minValue to make sure that I always get a value from my array. Now it's identifying that 1 and 8 are high and low values.
3:08 Now I can assign these values, so I can do low and constHigh and then I can use those in my array here. All of our tests are passing. If I come back in here and I start to mess with this array, we'll see that now our test fails because really, at this point, it should be looking for this as a result and our function is working regardless of which array we pass in.
3:42 Let's refactor this a little bit. I'm going to take this reducer function and I'm going to take up to the second argument. I'm going to cut that and I'm going to move L here and I'm going to create a new function that I'm going to call getLowest.
3:58 I'm going to set that to equal this call to reduce with min as a reducer, number.maxValue as the initial value and then we'll close that. Because Ramda's functions are auto carried, this is going to give me back a function that's now just waiting for that third argument, which is our array.
4:13 I'm going to do the same thing with our max reducer and I'm going to call this getHighest. Now we have getLowest and getHighest functions that we can call here, passing it numbers and we should get back the same results. As we can see from all the green boxes, our tests are still passing.
4:49 Let's take this a step further. I'm going to jump up to the imports here and I'm going to import another utility function from Ramda called converge. I'm going to use converge to combine these getLowest and getHighest functions into a single call that will give us back our array to use as our exclude list for without.
5:10 I'm going to call this getExclude and this is going to be a call to converge and converge's first argument is going to be a function. I'm going to define the function in line and I just want to take two values and return those two values in an array.
5:29 Essentially, this function is going to get our high value and our low value and give us the array that we can pass in as the first argument to without.
5:37 The second argument for converge is an array of transformation functions. In our case, we're going to use our getLowest and getHighest functions. This gives us back a function that we've assigned to getExclude.
5:52 The way this function works is it's going to take an argument and that argument in this case is going to be our numbers array. It's going to get passed to getHighest and we're going to get back a value. It's going to get passed to getLowest, we're going to get back a value.
6:06 Those values are going to be passed in to this converging function as our arguments. A is going to be the result from getLowest, B is going to be the result from getHighest and it's going to give us back our value, which in this case is going to be our array to pass to without.
6:23 Now I can come down here and I can get rid of these two calls and then I'm going to declare a const. I'll call it exclude and that's going to be a call to our getExclude function that I'm going to pass in numbers.
6:36 I'm going to come down here and I'm going to replace this array with that exclude value that we got from our converge function. We can see from our green boxes that our tests are passing now, so I'm going to clean this up. Let's get rid of these comments.
6:53 Let's take this one step further. I want to come up here and I need one more function from Ramda called identity. Then I'm going to drop down and I'm going to take this function and I'm going to comment it out, we're going to replace it. I'm going to export a const called dropHighLow.
7:12 I'm going to build the same functionality using another call to converge and this time, I'm going to use without as my converging function. As we can see from the commented out code, without takes two arguments. That means I want an array with two transformation functions, so that I can take the one argument that comes in to dropHighLow and get the values that I need into without.
7:37 The first argument for without was our exclude list and the function that will build that for us is getExclude. The second argument is numbers, which is going to be the value that's passed in to dropHighLow. I just need to pass that through and that's why we imported the identity function.
7:54 I use that here, we can save that. Now we have this point-free function, our test is still passing. If we come back over here and we start to manipulate numbers, we should expect that it will still pass when our input and our expected output match up.