WEBVTT

00:00:00.840 --> 00:00:05.950
There is an even better and shorter way to use this sort function. In

00:00:05.950 --> 00:00:10.450
C++20, we got introduced to the new concept of ranges.

00:00:11.040 --> 00:00:15.360
Ranges are abstraction on top of iterators. We can use them

00:00:15.370 --> 00:00:19.020
instead of explicitly providing iterator functions to

00:00:19.030 --> 00:00:22.180
algorithms like sort. To do this,

00:00:22.180 --> 00:00:25.960
we need to use the sort function from the range's namespace.

00:00:26.940 --> 00:00:30.480
Now we can just pass the array itself, because most sequential

00:00:30.480 --> 00:00:34.760
containers can be considered as a range. Range functions will

00:00:34.760 --> 00:00:38.520
implicitly look for iterators and use them instead of us,

00:00:38.530 --> 00:00:42.980
just like this range‑based for loop. If I compile this,

00:00:42.990 --> 00:00:46.840
you can see that this function works in the same way, but now the code is

00:00:46.840 --> 00:00:53.080
cleaner and uncluttered from iterators. Algorithms under this range's

00:00:53.080 --> 00:00:57.610
namespace are also known as constrained algorithms, because you only need

00:00:57.610 --> 00:00:59.560
to pass a range to make them work.

00:00:59.940 --> 00:01:03.370
Check out all of the available constrained algorithms on the CPP

00:01:03.370 --> 00:01:08.560
reference site. Just like iterators, ranges are a big topic,

00:01:08.560 --> 00:01:12.680
so we will just scratch the surface of their usage in regards to standard

00:01:12.680 --> 00:01:17.720
arrays. Ranges were previously available from the GitHub repository of a

00:01:17.720 --> 00:01:22.530
famous C++ developer, Eric Niebler, but since the C++20, they were

00:01:22.540 --> 00:01:25.060
officially added to the standard library.

00:01:25.740 --> 00:01:28.780
Now that we know how iterators work, I will turn this

00:01:28.780 --> 00:01:31.160
array back into a standard array.

00:01:31.840 --> 00:01:36.160
Let's say that I want to see the elements from this array in a different way.

00:01:36.540 --> 00:01:39.750
I want to filter out only the odd numbers and then

00:01:39.750 --> 00:01:41.850
multiply those numbers with 10.

00:01:42.440 --> 00:01:43.130
First,

00:01:43.140 --> 00:01:47.630
I will define another array of the same size in case all of the elements

00:01:47.640 --> 00:01:52.020
are odd numbers. Then I can use the copy_if function from the algorithm

00:01:52.020 --> 00:01:56.950
library to copy elements from the original array to this odd array. We

00:01:56.950 --> 00:02:00.490
need to provide both iterators from the first array, and the beginning

00:02:00.490 --> 00:02:02.440
iterator from the second one.

00:02:02.650 --> 00:02:05.530
The third argument is a function which will take in

00:02:05.540 --> 00:02:07.860
each element from the original array.

00:02:08.240 --> 00:02:12.260
Let's pass the lambda here, because we won't need this function later.

00:02:13.240 --> 00:02:16.460
This lambda will take in each element as a parameter,

00:02:16.460 --> 00:02:18.920
and if this function returns true,

00:02:18.930 --> 00:02:22.570
that element will be copied to the new array, and this

00:02:22.570 --> 00:02:25.250
will only be true if the element is odd.

00:02:25.640 --> 00:02:28.350
So this odd array will look something like this.

00:02:28.360 --> 00:02:32.910
It will contain all of the odd numbers, and since we have one even number,

00:02:32.920 --> 00:02:34.440
that place will stay 0.

00:02:34.810 --> 00:02:39.170
Usually, this element would be a garbage value, but by adding

00:02:39.170 --> 00:02:43.160
this empty initializer list, I instructed the compiler to set

00:02:43.170 --> 00:02:44.860
all of the array elements to 0.

00:02:45.940 --> 00:02:50.040
Okay, and now I need to multiply these numbers by 10.

00:02:50.050 --> 00:02:55.580
I need to create a new timesTenArr, and now let's use the

00:02:55.580 --> 00:02:58.210
transform function to modify each element.

00:02:58.220 --> 00:03:01.150
The function takes in the same set of arguments.

00:03:02.740 --> 00:03:05.990
The returned value from this lambda will be stored as an

00:03:05.990 --> 00:03:10.400
element of the new array, and that's it.

00:03:10.410 --> 00:03:13.260
Now I can output the elements to see if it worked.

00:03:14.040 --> 00:03:15.150
Let's compile this.

00:03:16.940 --> 00:03:18.400
It seems that it works.

00:03:18.410 --> 00:03:22.450
Although, I don't like this 0 at the end, but to fix that,

00:03:22.450 --> 00:03:25.700
we would need to somehow create a new smaller array of this

00:03:25.700 --> 00:03:29.450
specific size, and move non‑0 numbers there.

00:03:30.440 --> 00:03:34.780
But that would mean that I need to know the size of this small array at runtime,

00:03:34.790 --> 00:03:37.410
which means that I need to create some kind of a dynamic

00:03:37.410 --> 00:03:39.760
array, which complicates things even more.

00:03:40.140 --> 00:03:44.250
So much code for just a different perspective on the original array.

00:03:44.640 --> 00:03:48.990
We could have used the algorithm alternatives from the range's namespace,

00:03:48.990 --> 00:03:51.760
but this doesn't help much, we just avoid passing

00:03:51.760 --> 00:03:53.850
the iterators of the first array.

00:03:54.240 --> 00:03:57.820
Fortunately, constrained algorithms are not the only application of

00:03:57.820 --> 00:04:01.940
ranges, there is also a special ranges library, which provides us with

00:04:01.940 --> 00:04:04.350
new ways of working with sequential data.

00:04:04.740 --> 00:04:08.970
So, let's include that library. Ranges also provide

00:04:08.970 --> 00:04:13.420
us with the concept of views, which we can pipe together to create a chain,

00:04:13.430 --> 00:04:15.650
something like a UNIX pipeline.

00:04:16.540 --> 00:04:20.089
And now, instead of creating multiple intermediary arrays,

00:04:20.390 --> 00:04:25.700
I can just do everything here, inside of the loop. First, I want to pass

00:04:25.700 --> 00:04:29.250
this array to the filter function from the views namespace.

00:04:29.640 --> 00:04:32.040
I am using this pipe operator to do that.

00:04:32.050 --> 00:04:34.860
The output of the expression on the left is passed down to

00:04:34.860 --> 00:04:36.990
the input of the expression on the right,

00:04:37.000 --> 00:04:41.500
but in this case, this is done implicitly. We don't have to define any

00:04:41.500 --> 00:04:47.460
ranges or iterators. This function is known as an adapter, because it will

00:04:47.460 --> 00:04:50.760
take in a range and adapt it to something else.

00:04:51.140 --> 00:04:54.730
In this case, an input range is the array itself, and

00:04:54.730 --> 00:04:57.260
the output is something called a view.

00:04:57.640 --> 00:05:00.770
Views work kind of like temporary ranges.

00:05:00.780 --> 00:05:03.710
This filter function will create a temporary range,

00:05:03.710 --> 00:05:06.060
which only contains odd numbers.

00:05:06.440 --> 00:05:09.890
Filter function works kind of like a copy_if algorithm,

00:05:09.900 --> 00:05:13.060
but we only need to pass the lambda with the condition.

00:05:13.640 --> 00:05:16.250
The output of this function is a temporary range,

00:05:16.250 --> 00:05:19.760
which I then want to pass down to the transform function.

00:05:20.540 --> 00:05:23.910
Transform function will multiply all of the elements by

00:05:23.910 --> 00:05:26.660
10 and return another view.

00:05:27.540 --> 00:05:30.950
So, the for loop will actually loop over this final

00:05:30.950 --> 00:05:33.960
temporary range, or we can say, a view.

00:05:34.340 --> 00:05:37.820
We don't have to modify the original array or define other arrays to

00:05:37.820 --> 00:05:42.060
make the necessary modifications, we can just create a chain of views,

00:05:42.070 --> 00:05:44.470
and you can see the reason for that name,

00:05:44.480 --> 00:05:50.730
it gives us a different view of the original array. And, if I now compile this,

00:05:50.730 --> 00:05:54.760
you can see that the result is even better, no 0s at the end.

00:05:55.140 --> 00:05:59.360
The range's library is really powerful, so don't hesitate to use it.

00:06:00.440 --> 00:06:03.590
We're almost done with static arrays, I just want to mention

00:06:03.590 --> 00:06:06.810
a few more things. For the last example, let's create a

00:06:06.820 --> 00:06:09.470
two‑dimensional array. As we know,

00:06:09.480 --> 00:06:12.980
this is array of arrays, so I need to define the type of

00:06:12.980 --> 00:06:15.760
elements as another standard array.

00:06:16.740 --> 00:06:22.250
My 2d array will have two rows and three columns, so that means two

00:06:22.250 --> 00:06:26.920
smaller subarrays. Since standard array is a class, this array is

00:06:26.920 --> 00:06:31.430
actually an array of objects, and arrays of objects need to be

00:06:31.430 --> 00:06:33.370
initialized in a different way.

00:06:33.380 --> 00:06:37.060
You may think that something like this will work, we wrap all of the

00:06:37.060 --> 00:06:40.750
elements of the subarrays in special curly braces,

00:06:41.140 --> 00:06:44.940
but it won't, because when working with arrays of objects,

00:06:44.950 --> 00:06:48.360
this initializer list becomes ambiguous.

00:06:48.740 --> 00:06:51.760
You need to add another set of curly braces around the

00:06:51.760 --> 00:06:54.350
whole initializer list to make this work.

00:06:54.740 --> 00:06:57.780
The first set of braces is for the standard array class,

00:06:57.780 --> 00:07:01.200
the second one is for the internal array, and then all of these

00:07:01.200 --> 00:07:06.000
braces inside define the values for the specific object, in this

00:07:06.000 --> 00:07:09.950
case, the subarray. To see if this works,

00:07:09.960 --> 00:07:11.450
let's loop through the array.

00:07:12.340 --> 00:07:15.640
Since this is a 2d array, we'll need two for loops.

00:07:15.650 --> 00:07:18.720
The first one will loop over subarrays, and the second

00:07:18.720 --> 00:07:21.160
one over the elements of that subarray.

00:07:22.740 --> 00:07:26.730
We said that the implementation of this range‑based for loop looks

00:07:26.730 --> 00:07:31.180
something like this, but you can see that in each iteration, the row

00:07:31.180 --> 00:07:36.160
variable is making a copy from the value of the current element. Instead,

00:07:36.170 --> 00:07:40.490
we want to do something like this, to make this row variable a reference

00:07:40.490 --> 00:07:44.860
to the element itself. And we can definitely do this, we just need to turn

00:07:44.860 --> 00:07:49.850
this row alias into a reference. When working with objects, always use the

00:07:49.850 --> 00:07:54.040
range‑based loop like this, with references, because we don't want to make

00:07:54.040 --> 00:07:58.360
a copy of each element, this would degrade the overall performance.
