(bright music)
Presenter: Now that we've seen how
to implement both stateless
and stateful Lambdas, let's take a look
at more ways to use them.
The most predominant use of Lambdas
is in conjunction with the standard template
algorithms library
as either a predicate or operator.
Remember, a predicate is just a function
that takes several arguments and returns a Boolean.
Alternatively, an operator is a function that
takes several arguments
and applies some operation to them.
When using Lambdas with the STL Algorithms library
you'll often hear them referred
to as either unary binary predicates
or unary binary operations.
This simply refers to whether the Lambda will act
as a predicate or as an operator
and how many parameters the Lambda requires.
Unary meaning one and binary meaning two.
We've already seen lots
of examples that use Lambdas with the STL algorithms.
We've seen examples in this section
and we also saw examples
in the STL section of the course.
Now that we've got the jargon down
let's take a look at a few more examples
of how to use Lambdas with a few more STL algorithms.
Okay, so then let's go through some examples, in the IDE.
You can see here
that I'm in the section 21 workspace
and I'm in the STL underscore Lambdas project.
I've already gone ahead and built and run it.
You can see the run out here on the right side.
And let's go over the Includes IO stream vector algorithm
and I'm also including numeric.
This is for a function called iota, which is
a pretty handy little function that I haven't covered.
So I thought I would throw
it in just so you could learn it.
The algorithms that I'm gonna be using in here
are pretty straightforward ones.
There are a lot more of them,
as I said, please see your CPP reference.com website.
It's got documentation on all the STL algorithms.
Again, this video is not about the algorithms
it's about using Lambdas with them.
Let's go over some examples.
I've got I think seven tests that we'll run
and I'll walk through them just like I have before.
The first one we've already seen before.
It's for each.
Now I've included this as well as sort
in this video in case somebody jumps straight
into this video and they haven't seen them before.
They can see them here
for the first time
and I'll walk through them again.
Okay, so let's start with test one.
You can see test one's output
is right up here.
In test one, what we've got
is we're going over the, for each algorithm.
Now I've already covered the, for each algorithm a couple
of times in this section as well as in the course.
It's a very handy algorithm that lets you iterate
over a container in the standard template library.
So it's non modifying
so we're not gonna modify anything in the container.
It just basically processes each element, if you will.
In this case, I've got nums
which is a vector of five integers
and I've initialized it to 10, 20, 30, 40, 50.
And then what we're gonna do is we're gonna call for each
from the beginning to the end.
So we're gonna cover the entire container.
We don't have to, we can only loop, you know
once or twice or three or four elements, whatever we want.
But in this case, I'm iterating over the entire vector
and what's gonna happen
is for each element in that vector
it will be passed into this Lambda.
And we don't, we're not doing that right.
The for each algorithm is doing that.
And then we just use this Lambda as an operator here
not a predicate, it's just a regular operator.
We just do some stuff.
So in this case we're just displaying.
So it's gonna iterate, pass those guys in.
Notice there's no capture.
We only have that one parameter which we need
because for each is giving it to us
and it's just going to display 10, 20, 30, 40, 50.
So this is a really,
really simple example of using a Lambda
with one of the algorithms
in the standard template library.
A very handy algorithm as well.
I'm using it here, but this can be a container of anything.
Okay, so let's take a look
at a different one
that we probably haven't seen before.
This one is called is permutation.
This one is called is permutation
and it's also non modifying.
In this case I'm using triangles.
So it tests whether two triangles are equivalent
and we defining a triangle being equivalent
as a triangle as a vector of three points in any order.
So regardless of the order, if two triangles
contain those same three points, they're equivalent.
So pretty simple definition.
So before we use the algorithm
let's take a look at what we've done.
Let me scroll up just a little bit here.
So here's test two
and you can see test two's output right over here.
And I've got a structure that I've defined called point
which is just an x, y attribute.
And then I'm gonna create four points, point one,
point two, point three, point four.
And based on those points I'm gonna create a triangle.
So a triangle is a vector of points, three points,
triangle one is point one, point two,
point three, triangle two is point two,
point three, point one.
And then triangle four includes that point four here.
So according to our definition, these two are equivalent
because we can change the order, right?
I think everybody understands
what a permutation is,
we're just kind of mixing these things
up in different orders.
Eventually we can permute one of these and get one of those.
'Cause we've got one, two, three in both of them.
However, triangle three is not equivalent
because that point four doesn't exist
in either triangle one or triangle two.
And again, the important thing is the Lambda here
so I'm going to call stood is permutation.
I'm going to pass in triangle one begin,
triangle one end that's going
from the beginning to the end of this vector.
And then I'm passing in triangle two begin.
Let me spread this out just a little so you can see it.
So we are also expecting two points.
Now the stood is permutation function.
That's what it's doing.
It's passing those two points into us
and it's up to us to compare them however we like.
So we're creating the left hand side
and the right hand side
and it's using the operator equal to compare.
So what's gonna happen is I'm gonna compare my
left hand side's x to my right hand side's x
and the left hand side's y to the right hand side y.
So our points are equivalent.
So when we call is permutation
and we get a permutation that matches one of those
we've got an equivalence and that's pretty much it.
So we're using that in the if statement
and if they're equivalent,
we're just displaying that.
If they're not equivalent,
we're displaying that.
And you can see from this test case right here
that triangle one and triangle two are equivalent.
And that's exactly what's being displayed right over here.
Let me move this back
'cause I think everybody sees what's going on now.
In the other example down here
I'm using triangle one and triangle three.
Now remember triangle three
has that fourth point in there
so it's not going to be equivalent.
And that's exactly what happens right here.
We've got triangle one,
triangle three are not equivalent.
So again, just another example of passing in a Lambda here
this Lambda does not capture and it expects two parameters.
In this case, this is a predicate Lambda
because it's returning a true false value.
Alright, so let's move on to test three.
In test three, I'm using the transform algorithm.
This is a modifying operation
and if you recall in the previous examples, we created
that Lambda bonus where we awarded bonus points
to test scores and so forth.
Well, we're gonna do the same thing
except we're gonna use to transform.
So let's do it.
We've got test scores and it is a vector of integers.
And those are my test scores, 93, 88, 75, 68, 65.
And these are the bonus points that I want to add
to each one of those test scores.
Right away you know we've got a local variable here.
If we're gonna use that in the Lambda
we need to capture it.
So that's what we're going to do in this example.
We are going to transform that container test
scores begin test scores dot end.
So we're doing the entire container
and we're gonna start writing
back the information at test scores dot begin.
So we're gonna start from here
and we're gonna start updating from here as well.
We're capturing bonus points by value.
That's this guy right here.
So we're gonna capture those bonus points
by value and then it stood
transform is going to pass into the Lambda
each one of those scores as it iterates over it.
So those scores will be passed into here, 93
then 88 and 75 and so forth.
So what we're doing now is we're returning score
plus equals five in this case.
So what we're going to do is we're gonna increment each one
of those test scores by five points.
So let's take a look at the output right over here
right here you can see I'm in test three
and you can see right there that we've gone from 93 to 98
from 88 to 93 and so forth.
So we've added five points to each one of those scores.
I just used a range based for loop here.
I could have used the for each algorithm as well.
I'll leave that up to you guys to decide.
Okay, so let's take a look at test four.
I've got a vector of integer called nums
and you can see I've initialized it here
to one, two, three, four, five.
Now what we're going to do is we're gonna remove
the even numbers from that vector.
Then once we remove them, we're going to erase them.
So what we're doing here is first we're calling remove if
and we're telling remove if that we want to want to iterate
over the entire container numbs from beginning to end.
And what remove if will do is it will pass in each one
of those values from that container into this Lambda.
This is a predicate Lambda
and we're returning true for whatever we want to delete.
So in this case, we're returning true for all even numbers.
So two and four are what we want to eventually erase
which right now we're just removing.
What happens is it puts those numbers
at the end and sets the end to it.
So now we're telling nums dot erase
to erase what it returned
and use nums dot end as the new end.
So it's basically they're gonna chop off those numbers.
And then when we display our updated numbers
you can see right there one, three and five.
So again, another example of using a predicate Lambda
this is using the erase remove idiom
which is a very common idiom in the STL.
Okay, so let's move on to test five.
In test five, I'm using that same person class
that I've used throughout this section.
So it's right here.
You can see it's that person class
with our overloaded insertion operator.
We've got our name, our age, and a bunch of constructors
and getters and setters.
So you can refer to the previous videos where
I explained this in a little bit more detail.
So what we're gonna do now is we're gonna sort it.
Now you've seen this before in the previous video.
I just wanted to include it again just to be complete
because somebody may jump into this video and not
have any idea how sort works.
So now you know.
So in this case, really easy.
I've created three person objects, person one, person two
and person three.
You can see them right here, Larry Moe, Curly.
Then I've created a person vector and I've just
created it using person one, two and three.
I've initialized it to those person objects.
This is just another way to do it.
I believe I've done it in the other videos just using move.
And then we're going to call std sort
and we're gonna tell std sort
that we want to sort that people vector
from begin to end and I want it to pass me pairs
of persons where that I need to compare.
So it's going to send to me two person objects
one on the left, one on the right
and we're using the less than operator to compare those two
and we're gonna compare by name.
So in this case you can see we're just comparing
by name and we're sorting in increasing alphabetical order
and then we're displaying these.
So what's gonna happen is right here
Curly, Larry and Moe, clm , right?
So it's in alphabetical order.
So in this case, if we wanted to display the people
in that vector by age and in descending order
then we would just have to say left hand side
get age greater than right hand side
get age and it will display Moe, Curly
and Larry in that order 30, 25, 18 and descending age.
Really powerful stuff.
All we're doing is changing that Lambda,
changing that predicate Lambda to do what we need.
It's our functional requirements.
If we have to sort by name ascending
or by age descending, it's really, really easy to do.
Alright, so let's move on
to another one that's a little bit different.
In this case, I've written a function
and that function is called in between.
That function expects a vector
of numbers, integer in this case, and I'm passing
that in by const ref, a start value
and an end value is going to decide
whether all the numbers in that vector are
between that start value and that end value inclusive.
I'm going to use the stood all of algorithm.
It's a non modifying algorithm and what it does is it tests
whether all the elements contained
within the sequence satisfy the condition in the Lambda.
So in this case I'm assuming that they don't.
So I'm just initializing this result bullying
to faults and then I'm saying result equals stood all
of where do I want to start?
I want to start at nums dot begin
and I want to go all the way to nums to end.
So again the entire container
I need start value and end value.
So I need to capture those guys
and that's what's happening right here in the capture list.
I need to know what they are to be able to use them
in my Lambda right in here.
And what stood all of is going to do is for each element
in that container, it's gonna pass it into this Lambda
and all I'm gonna do is I'm gonna say return.
If the value is between start value and end value
that's what that logic is saying right here
I'm gonna return result.
So really straightforward, really powerful too.
We don't have to deal with any of this ourselves.
We just here is test six
let me scroll this up a little bit as well.
So you can see the test six output right up here.
And here's test six, I'm setting std bull alpha just
so I can display true faults rather than zero one.
So I'm starting with a vector of 10 integers called num.
I'm using parenths here, not curly.
So I'm not initializing the first element
of that vector to 10.
I'm creating a vector of 10 elements
and then I'm using that iota function,
which is in the numeric library.
And what it does, it goes
from nums dot begin to nums dot end and I'm providing one.
So basically what it's going to do is it's gonna
set the values in those 10 integers
to one, two, three, four, five, all the way to 10.
If I'd have started this at 10 in here
it would go from 10, 11, 12 and so forth.
Really handy way assigned values
to an existing container in incrementing order.
So I'm displaying that and you can see right there
that's exactly what iota has done.
One through 10 is, I'm gonna call in between
that's my function that I wrote up here.
I'm gonna pass in the vector
I'm gonna pass in the start and the end.
And what it's going to do is gonna check to see
if every element in that container
is between 50 and 60.
Well that's not true, right?
Because the container contains one through 10.
So they're not all between 50 and 60
in fact none of them are between 50 and 60.
So that's gonna return false.
In this case I'm gonna check to see
if the numbers are between one and 10.
Well they are, it's returning true
and in this case I want to check to see
if the numbers are between five and seven.
Of course they're not.
So that returns false as well.
Okay, so then finally we're at the last test here
test seven, and this was a little bit more complicated
but it's pretty cool.
We have a class called password validator
and it contains an attribute called restricted symbol.
And in this case this is a single character
that's the dollar sign.
So basically passwords cannot have dollar signs in them.
Then I've got a method called is valid.
So we're gonna pass in a password and this method
is going to tell us whether it's a valid, well it is
valid if it doesn't contain that one simple in this example.
So what this is going to do,
it's going to check all of the characters
in the password and be sure that none of them
are the dollar sign, right?
And we could write loops and we could do all kinds
of stuff to do this ourselves
but why not use the algorithm all of.
So let's do that.
I'm checking password
from begin to end password is a string.
So it's basically a container of characters.
And again, I'm using stood o
of I need to capture this object
because I need access to that guy right there.
Restricted symbol.
So remember we're capturing the object here
the pointer all of will pass
in each character of the password into this Lambda.
So now we have everything we need
and this will return character not equal
to restricted symbol.
So this, if the character is not equal
to the restricted symbol, we've got a valid password
and that has to happen for all of the characters.
If any of those fail, it's going to return false.
Pretty cool.
So let's see how we would use it.
I've got another example down here that I'll go over
in a second, but let's take a look
at the all of and how we would use it right there.
So we've got a password
we're creating called Hollywood one
with a dollar sign at the end.
So this is an invalid password because of that guy.
Now I'm instantiating my password validator
and I'm just simply calling PV one dot is valid
and I'm passing the password into it.
That's it.
Simple as that.
It's going to return true
if the password is valid, false if it's invalid, well
in this case we know that that password is not valid
because it has the dollar sign in it.
If we change the password to just Hollywood one
and execute this code, it will display is valid.
Okay, so hopefully that makes sense.
You can see what's happening.
It's pretty easy.
We've got characters coming
in from that password string
and we're comparing 'em to that restricted symbol.
We need to capture, we need
to capture the this pointer
otherwise we won't have access to a restricted symbol.
Let's take a look at another example.
This is very, very similar.
This is password validator two.
The big difference here
is I don't have a single character
of restricted symbols.
I've got a vector of restricted symbols.
So in this case I've got a vector of characters.
The bang, the dollar
and the plus symbol are all restricted.
That would make it an invalid password.
It changes our logic a little bit
but you can see the power here,
I've still got my is valid method
that expects that password.
But what's gonna happen now is I'm gonna use all
of and none of together.
Now that's pretty cool.
So let me show you how that works.
So you could walk through this really carefully
but basically what it's doing,
it's making sure that all
of the characters in the password are not restricted.
And in order to do that
we're using stood all of and stood none of.
So again, what we're doing is we're making sure
that all of the characters
in the password have none
of the restricted symbols in them.
And if we run this example
we've got C++ rocks that has a bunch
of illegal characters in it, right?
It's got the plus and the bang.
So we're initializing PV two
and we're checking whether it's valid password or not.
Well, it's not valid
because it's got the pluses and the bang.
In this case we've got a single
bang that's also not valid.
And then in this case we have none of those characters.
Therefore the password is valid.
In this video we've seen some common STL algorithms
and how to use Lambda with them.
But it's important to note
that this in no way covers them all.
There are many, many algorithms
in the STL algorithms library that use Lambdas
and as we saw what the class password validator too
that can even be used in conjunction with one another.
It would be impossible to cover them all.
But hopefully this gives you a good understanding
of why Lambdas are so important and their patterns of use.
Learn the STL algorithms
they'll become your best friends.
Also, if you're a competitive programmer
consider using the STL algorithms
before you code your own solution.
Okay, so that wraps up this section on Lambdas.
I hope you find this section useful.