Question function ?

andrews

Well-known member
Joined
Nov 22, 2011
Messages
167
Programming Experience
5-10
I want to have a function
I have an array ar(300) as integer
There are different integers but also same integers in the ar
I wanted to know the sum of all integers who are different and how many there are who are different
Example
ar(1) = 1
ar(2) = 4
ar(3) = 4
ar(4) = 5
ar(5) = 6
ar(6) = 6
ar(7) = 8
ar(8) = 9


function(byref ar as integer, number as integer) as integer
array.sort(ar)
.....
end function


result
number = 4
function = 23


But, the function has to be very performant.
My question:
Can we get the result by running 1 time the ar.
for i = 1 to ar.getupperbound(0)
....
...
next
giving number and sum
Thanks for any response
 
First things first, this:
VB.NET:
function(byref ar as integer, number as integer) as integer
is wrong. The first parameter should be ByVal, not ByRef, and it must be Integer(), not Integer.

Apart from that, the simplest option is to simply call the Distinct method of your array and then the Sum method of that result.
 
Thanks for your response.
I know how to make a function in general way.


Private Function SomgDistincts(ByRef ar() As Integer, ByRef HowMany As Integer) As Integer
.....
End Function


Concerning given array parameters in a function or sub it is always ByREf even writing Byval.
I do not know the Distinct method but if it is a Linq method I know that it is not performant considering time.
The best method should be what I have asked but I do not know if it exists.
By the way, I have two solutions for this problem but not the fastest way I suppose.
That is the reason I asked to run only one time in the array.
I do not know if it is possible.
 
Concerning given array parameters in a function or sub it is always ByREf even writing Byval.
No, that is wrong. An array is a reference type object, that is true, but there is still a difference between declaring a parameter ByRef and ByVal. If you declare it ByVal then a copy of the reference is made and passed. If you declare ByRef then a reference to the reference is created and passed. You should ALWAYS declare a parameter ByVal unless you specifically need to declare it ByRef. In the case of reference types, you only need to declare a parameter ByRef if you need to assign a new different object to the parameter inside the method and have that change affect the original reference. You are not assigning a new array to the parameter inside your method so you do NOT need to declare it ByRef so it should be ByVal.
 
I haven't done any testing so I don't know what performance would be like for different options. The fact is though that, if you want to use distinct values, you need to record each value that has been used and then each time you need to decide whether to use a value or not you have to check whether that value has already been used. Direct comparisons are bound to be slow so I would think that using hash values would improve performance. You may be able to speed things up more by writing more of the infrastructure yourself but here's a simple option that implicitly uses hashes:
Private Function SumDistinct(numbers As IEnumerable(Of Integer)) As Integer
    Dim distinctNumbers As New HashSet(Of Integer)
    Dim sum As Integer

    For Each number In numbers
        'Add will return True if and only if number is not already in the set.
        If distinctNumbers.Add(number) Then
            sum += number
        End If
    Next

    Return sum
End Function
 
Sorry, I see no difference when you write ByRef or ByVal, it is he same array.
How do you explain

Private Sub testref(ByRef array1() As Integer)
array1(1) = 1000
End Sub


Private Sub testbyv(ByVal array2() As Integer)
array2(1) = 1000
End Sub


Dim arr(3) As Integer


arr(1) = 1
arr(2) = 2
arr(3) = 3


testref(arr)
MessageBox.Show(arr(1))
testbyv(arr)
MessageBox.Show(arr(1))

Two times I get 1000, saying that array1 and array2 are arr.
 
Try this instead:
    Sub deref1(ByVal arr As Integer())
        arr = Nothing
    End Sub

    Sub deref2(ByRef arr As Integer())
        arr = Nothing
    End Sub

        Dim arr = {1, 2, 3}
        deref1(arr)
        MessageBox.Show(arr(1))
        deref2(arr)
        MessageBox.Show(arr(1))
 
Yes, there are two indications (mine and yours) who seems contradictory.
Can you give a good explanation, JohnH.
 
Your example is just accessing an element within the array object, this has nothing to do with ByVal/ByRef.
My example show what you can do with a ByRef parameter that you can't with a ByVal parameter. The example assigns (or not) the null reference Nothing, but it can be any object reference.

ByRef is sometimes used to allow output parameters for value types, that means method can assign a new value to the parameter and caller gets the value returned through the variable that was passed as argument. For reference types that is irrelevant, unless the method needs to assign a new object (which is rare and not recommended). Code conventions is in most cases to use function returns instead.
 
Whether or not you understand the mechanisms involved, the rules are very simple: use ByVal unless you have a specific need to use ByRef. If you're not sure which to use in a specific case then use ByVal and only switch to ByRef if ByVal doesn't work.
 
From VS 2010 SP1 specifying the default ByVal is no longer mandatory, when you add parameters IDE will no longer add ByVal to it. So in new code you should no longer see any ByVal, and normally you should see no ByRef either :)
 
Hi andrews,

In addition to all the great advice you have received from the forum experts, maybe this can help you understand better the ByVal vs ByRef issue. This is how I was taught many years ago. I am sure that .NET has many more implications nowadays but this is an easy way to get your head round this question to begin with.

Add the following code to a new form and run. Really simple, but then read the comments to fully understand what is happening.

Hope it helps,

Cheers,

Ian

VB.NET:
  Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    Dim My_ByVal_Variable As Integer = 10
    Dim My_ByRef_Variable As Integer = 10
 
    'show the current variable value that was defined in this context. That being 10
    MsgBox(My_ByVal_Variable)
    Change_ByVal_Variable(My_ByVal_Variable)
    'show the current variable value that was defined in this context after a call was made to Change_ByVal_Variable sending the My_ByVal_Variable as a parameter
    'Notice - There is no change to the variable value that was defined in this context
    'This is because when using ByVal you are creating a new instance of this passed variable in the subroutine that is totally independant of the variable that was created in this context
    MsgBox(My_ByVal_Variable)
 
    'show the current variable value that was defined in this context. That being 10
    MsgBox(My_ByRef_Variable)
    Change_ByRef_Variable(My_ByRef_Variable)
    'show the current variable value that was defined in this context after a call was made to Change_ByRef_Variable sending the My_ByRef_Variable as a parameter
    'NOTICE - the variable that was defined in this context has now changed to reflact any changes that were made to the passed variable in the subroutine that was called
    'This is because when using ByRef you are actually creating a pointer to the original variable that was defined from this context and passed to the subroutine
    MsgBox(My_ByRef_Variable)
  End Sub
 
  Private Sub Change_ByRef_Variable(ByRef ReceivedVariable As Integer)
    ReceivedVariable = 20
  End Sub
 
  Private Sub Change_ByVal_Variable(ByVal ReceivedVariable As Integer)
    ReceivedVariable = 20
  End Sub
 
Back
Top