Page 1 of 1

Predicates (For vb.net 2.0 and above) Rate Topic: ***** 1 Votes

#1 thava  Icon User is online

  • D.I.C Lover
  • member icon

Reputation: 179
  • Posts: 1,599
  • Joined: 17-April 07

Posted 22 February 2013 - 03:02 AM

What is a Predicate?
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

Is This A Good Question/Topic? 0
  • +

Page 1 of 1