As per Microsoft Explanation
A function that defines a set of criteria and determines whether the specified object meets those criteria.
To me, simply said that it is a Function which has only one parameter and it always return a boolen value
based on the logical operations performed for that parameter
Why predicate?
Most of the time people ask this question in the web
let us consider this , a client has list of integers he want's to the count following
1) the multiple of 5
2) the multiple of 10,
3) the multiple of 5 and not multiple of 10
i have created a list of integers,using the following code
lstNumbers = New List(Of Integer)
For i = 0 To 10000
Dim r As New Random
Dim rnd As Integer = r.Next(0, i)
lstNumbers.Add(rnd)
ListBox1.Items.Add(rnd)
Next
Now,i Want to get the multiple of 5
Dim Lstfive As New List(Of Integer) For Each num As Integer In lstNumbers If num Mod 5 = 0 Then Lstfive.Add(num) End If Next
this result contains the zero values
since this results contains with 0 values i want to eliminate zeros
For this i have two options
1) create the result list again with the new for loop
2) delete the zeros from the result list using a new for loop
i go with the first one and create the result again
Dim lstFive As New List(Of Integer)
For Each num As Integer In lstNumbers
If num Mod 5 = 0 And num <> 0 Then
lstFive.Add(num)
End If
Next
MessageBox.Show(lstFive.Count)
Now i want to get the Multiple of 10
Dim lstTen As New List(Of Integer)
For Each num As Integer In lstNumbers
If num Mod 10 = 0 And num <> 0 Then
lstTen.Add(num)
End If
Next
MessageBox.Show(lstTen.Count)
Now i want to get the count of the multiple of 5 and not the Multiple of 10 for this i have two option
1) Create the result list again with the new for loop
2) Just subtract the lstFive.count-lstTen.count
If I go with first option I need to create a Loop again so I am going to choose the second option
Since I have lstFive and lstTen both lists are filled
MessageBox.Show(lstFive.Count - lstTen.Count)
Now i want to add an extra option with this program let the user choose choice what he want, either it's multiple of 5 or multiple of 10 or multiple of 5 but not multiple of 10
Now the code look like this (since I used the winform i used Radio options here)
Dim res As New List(Of Integer)
If RadioButton1.Checked Then
For Each num As Integer In lstNumbers
If num Mod 5 = 0 Then
res.Add(num)
End If
Next
ElseIf RadioButton2.Checked Then
For Each num As Integer In lstNumbers
If num Mod 5 = 0 And num <> 0 Then
res.Add(num)
End If
Next
End If
MessageBox.Show(res.Count)
Now just think if we want to work out this in an array of numbers and perform the same operation again, what will happen the code will get double again
you may said that create a function or procedure to reduce the code but list of numbers and array of numbers are not equal, so we need to convert the array to list and pass to that function we need a conversion here
Adding some more conditions then the whole code will become looks like the following code
Dim res As New List(Of Integer) If Rdoby5.Checked = True Then For Each num As Integer In lstNumbers If num Mod 5 = 0 Then res.Add(num) End If Next ElseIf rdoby10.Checked = True Then For Each num As Integer In lstNumbers If num Mod 10 = 0 Then res.Add(num) End If Next ElseIf Rdoby5NotZero.Checked = True Then For Each num As Integer In lstNumbers If num Mod 5 = 0 And num <> 0 Then res.Add(num) End If Next ElseIf rdoby10NotZero.Checked = True Then For Each num As Integer In lstNumbers If num Mod 10 = 0 And num <> 0 Then res.Add(num) End If Next ElseIf RdoNonZeronumbers.Checked = True Then For Each num As Integer In lstNumbers If num <> 0 Then res.Add(num) End If Next Else For Each num As Integer In lstNumbers If num Mod 5 = 0 And num Mod 2 <> 0 Then res.Add(num) End If Next End If MsgBox(res.Count)
Now let us see how predicate works, i already give a little explanation about Predicate in my point of view
a predicate is a function which returns always a boolean value with one parameter so its look like this
Private/Public Function <Function Name>(ByVal X As <Any Type you want to process>) As Boolean
'Process x here and return the boolean
Return (True/ False)
End Function
Let's go from the begining
i Want to get the multiple of 5 For that i create a function like this
Private Function multipleOfFive(ByVal i As Integer) As Boolean
Return (i Mod 5 = 0)
End Function
Take a close look of the function it has only one parameter which is integer since i am going to work with integer and the return type is Boolean
Now how can i use this
Dim lstfive As New List(Of Integer) lstfive.AddRange(lstNumbers.FindAll(AddressOf multipleOfFive))
you can use the same function for the array also
ArrNumbers.FindAll(AddressOf multipleOfFive))
since this results contains with 0 values i want to eliminate zeros
so I have to create a new function from the previous function and refine the result
Private Function IsNonZero(i As Integer) As Boolean
Return i <> 0
End Function
Private Function multipleOfFiveNotZero(ByVal i As Integer) As Boolean
Return multipleOfFive(i) And IsNonZero (i)
End Function
Dim lstFive As New List(Of Integer)
lstFive.AddRange(lstNumbers.FindAll(AddressOf multipleOfFiveNotZero))
MessageBox.Show(lstFive.Count)
Multiple of 10
For that I create a new function from the previous function
Private Function multipleOfTen(ByVal i As Integer) As Boolean
Return multipleOfFiveNotZero(i) And (i Mod 2 = 0)
End Function
Dim lstTen As New List(Of Integer)
lstTen.AddRange(lstNumbers.FindAll(AddressOf multipleOfTen))
MessageBox.Show(lstTen.Count)
Multiple of 5 but not Multiple of 10
Dim lstFiveOnly As New List(Of Integer)
lstFiveOnly.AddRange(lstNumbers.FindAll(AddressOf multipleOfFiveNotZero))
'since it contains the Multiple of 10 remove the 10
lstFiveOnly.RemoveAll(AddressOf multipleOfTen)
MsgBox(lstFiveOnly.Count)
if you look at the above code, just the same function(multipleofTen) is used to Remove the numbers also Think how much code is reduced and how much readable is this
Now look at the One more Special
i want to add an extra option with this program let the user choose the choice what he want, either it's multiple of 5 or multiple of 10 or multiple of 5 but not multiple of 10 Now the code look like this(since i used the winform i used Radio options here)
Dim res As New List(Of Integer)
Dim lstfive As New List(Of Integer)
lstfive.AddRange(lstNumbers.FindAll(AddressOf multipleOfFive))
If Rdoby5.Checked = True Then
res.AddRange(lstfive)
ElseIf rdoby10.Checked = True Then
res.AddRange(lstfive.FindAll(AddressOf multipleOfTen))
ElseIf Rdoby5NotZero.Checked = True Then
lstfive.RemoveAll(AddressOf IsNonZero)
res.AddRange(lstfive)
ElseIf rdoby10NotZero.Checked = True Then
res.AddRange(lstfive.FindAll(AddressOf multipleOfTen))
res.RemoveAll(AddressOf IsNonZero)
ElseIf RdoNonZeronumbers.Checked = True Then
res.AddRange(lstNumbers.FindAll(AddressOf IsNonZero))
Else
lstfive.RemoveAll(AddressOf multipleOfTen)
res.AddRange(lstfive)
End If
MsgBox(res.Count)
you may thought "is it a special one", well that's not the special one, adding one more implementation to maintain readability of the code I re write it with the predicate declaration see the following code
On the whole it's look like this
Private Sub btnByPredicate_Click(sender As System.Object, e As System.EventArgs) Handles btnByPredicate.Click
Dim res As New List(Of Integer)
'Dim lstfive As New List(Of Integer)
'lstfive.AddRange(lstNumbers.FindAll(AddressOf multipleOfFive))
'If Rdoby5.Checked = True Then
' res.AddRange(lstfive)
'ElseIf rdoby10.Checked = True Then
' res.AddRange(lstfive.FindAll(AddressOf multipleOfTen))
'ElseIf Rdoby5NotZero.Checked = True Then
' lstfive.RemoveAll(AddressOf IsNonZero)
' res.AddRange(lstfive)
'ElseIf rdoby10NotZero.Checked = True Then
' res.AddRange(lstfive.FindAll(AddressOf multipleOfTen))
' res.RemoveAll(AddressOf IsNonZero)
'ElseIf RdoNonZeronumbers.Checked = True Then
' res.AddRange(lstNumbers.FindAll(AddressOf IsNonZero))
'Else
' lstfive.RemoveAll(AddressOf multipleOfTen)
' res.AddRange(lstfive)
'End If
'MsgBox(res.Count)
Dim prdNumbers As System.Predicate(Of Integer)
If Rdoby5.Checked = True Then
prdNumbers = AddressOf multipleOfFive
ElseIf rdoby10.Checked = True Then
prdNumbers = AddressOf multipleOfTen
ElseIf Rdoby5NotZero.Checked = True Then
prdNumbers = AddressOf multipleOfFiveNotZero
ElseIf rdoby10NotZero.Checked = True Then
prdNumbers = AddressOf multipleOfTenNotZero
ElseIf RdoNonZeronumbers.Checked = True Then
prdNumbers = AddressOf IsNonZero
Else
prdNumbers = AddressOf multipleOfFiveNotTen
End If
res.AddRange(lstNumbers.FindAll(prdNumbers))
MsgBox(res.Count)
End Sub
Private Function IsNonZero(i As Integer) As Boolean
Return i <> 0
End Function
Private Function multipleOfFive(ByVal i As Integer) As Boolean
Return (i Mod 5 = 0)
End Function
Private Function multipleOfTen(ByVal i As Integer) As Boolean
Return multipleOfFive(i) And (i Mod 2 = 0)
End Function
Private Function multipleOfFiveNotZero(ByVal i As Integer) As Boolean
Return multipleOfFive(i) And IsNonZero(i)
End Function
Private Function multipleOfTenNotZero(ByVal i As Integer) As Boolean
'Return multipleOfFiveNotZero(i) And (i Mod 2 = 0)
Return multipleOfTen(i) And IsNonZero(i)
End Function
Private Function multipleOfFiveNotTen(ByVal i As Integer) As Boolean
'Return multipleOfFive(i) And (i Mod 10 <> 0)
'Return multipleOfFive(i) And Not multipleOfTen(i)
Return multipleOfFive(i) And (i Mod 2 <> 0)
End Function
Spoiler
Now consider the situation after a long time,
The client just say that, "sorry i am wrong, I don't want the multiple of 5, I just want the multiple of 2", You know Which one is easier and which one is tougher to understand and change,
Quote
You said “okay, what’s there? At any cost I have to change the code, i need to write a function for every divisor that the client ask? because, It seems everything inside a predicate is predefined(Fixed)"
Well now you have a question, is everything inside a predicate is fixed?
My answer is no you can tweak it
I have given an example of how you can use it
See the below class
Public Class MyIntegerFinder
Private _Divisor As Integer
Public Property Divisor As Integer
Get
Return _Divisor
End Get
Set(value As Integer)
_Divisor = value
End Set
End Property
Public Function MultipleofDivisor(ByVal i As Integer) As Boolean
Return i Mod Divisor = 0
End Function
Public Function MultipleofDivisorWithoutZero(ByVal i As Integer) As Boolean
Return (i Mod Divisor = 0) and i <>0
End Function
End Class
Now you can use this class as your divisor class like this
Dim c As New MyIntegerFinder c.Divisor = CInt(TextBox1.Text) MessageBox.Show(lstNumbers.FindAll(AddressOf c.MultipleofDivisor).Count.ToString)
Will it be more useful in the future isn't it, the client may add any number of divisor he wants,
hope you understand the predicates and enjoy the tutorial, happy coding






MultiQuote


|