Hello There, Guest!
View New Posts  |  View Today's Posts
Visual Basic Cookbook

  • 0 Vote(s) - 0 Average
Thread Closed 


11-17-2014, 05:39 PM #1
Null
Moderator
*****
Moderators
Posts: 130 Threads:23 Joined: Feb 2012 Reputation: 4

Visual Basic Cookbook
I originally published these short tutorials on another forum back in 2013 however, I am cross-posting them here as this is a much better platform. I do not, however, intend to update this post anytime soon, sorry.]

Welcome To My Visual Basic Cookbook:
A programming cookbook is essentially a collection of ready to use, cut and paste segments of code (recipes) to solve a specific problem. I hope that in posting a recipe here every day or so you guys will either find my recipe immediately useful or simply acknowledge such a recipe exists in this thread for future reference.

Table Of Contents:
(Note that this thread will always be closed. I intend to reserve a post for each recipe.)

How To Split a Collection Into Smaller Subsets (chunks):
I have been asked by proficient programmers "how to split an array into smaller chunks?" on more than one occasion. I think that the reason many people struggle to approach this problem is because there are so many different solutions - so many so, that the programmer soon becomes overwhelmed. This is obviously not true for everybody, and in all honesty I am talking about a minority here, but the point remains. There are a many ways to tackle this problem.

I experimented with a few different algorithms and I found the following to work the best in terms of functionality and readability:

Code:
''' <summary>
''' Splits the given collection into smaller sub-sets (chunks).
''' </summary>
''' <param name="collection">The collection to split into chunks.</param>
''' <param name="chunkSize">The maximum chunk size.</param>
''' <remarks>
''' If the number of elements in the given collection is not immediately divisble by the maximum chunk size then the
''' final chunk will contain the remaining (N of elements % chunkSize) elements.
''' </remarks>
<Extension()>
Public Iterator Function Chunk(Of T)(ByVal collection As IEnumerable(Of T), ByVal chunkSize As Integer) As IEnumerable(Of IList(Of T))
    Dim currentChunk As List(Of T) = New List(Of T)(chunkSize)
    For Each element As T In collection
  currentChunk.Add(element)
  If currentChunk.Count = chunkSize Then
    Yield currentChunk
    currentChunk = New List(Of T)(chunkSize)
  End If
    Next

    If currentChunk.Count >= 1 Then
  Yield currentChunk
    End If
End Function

The algorithm simply iterates over each element in the given collection, adding each element to a sublist of N size where N equals the given maximum sublist size. When the sublist is full, the sublist is effectively returned to the caller. The algorithm then proceeds to clear the sublist and then repeat the aforementioned steps. If there are no more elements left in the given collection but the sublist is not yet full, the sublist will effectively be returned to the caller regardless of the size. This means that the last sublist (or chunk) omitted by the Chunk function might differ in size compared to the proceeding chunks.

Note that the function is defined as an extension method and that the method is largely leveraged by the yield statement.

How To Compare Collections For Equality:
So you want to determine whether two collections are equal. The answer is seemingly obvious, use the = operator right? ... Not quite D:

Should you try and compare two collections (e.g. two arrays) using the = operator you will be presented with a compile-time error. Put simply, the problem is that the System.Array class does not really define any logic to compare two arrays for equality. Another (and more elaborate) way to word this description of the problem is that the System.Array class does not overload the = operator and it is because of this that a compile-time error will be presented.

As with the previous recipe, there are a number of ways to approach this problem. This is true for almost every recipe, but the reason I emphasize this, is because the following method is far from optimal. You have to understand that comparing two collections for equality can potentially be an expensive operation, especially when dealing with big collections.

Code:
Private Function UnanimousCollection(Of T)(ByVal firstList As List(Of T), ByVal secondList As List(Of T)) As Boolean
    Return firstList.SequenceEqual(secondList)
End Function

The most apparent way to improve the performance of the aforementioned code is to only enumerate the collection, checking for sequential equality, if the equality of the collections cannot already be determined from another source. Consider the following minor adjustments that you could make to the aforementioned code listing in order to improve the performance:
  • Check that the given arguments for nullity:
    • There is no need to enumerate the collection, checking for equality if either (or both) of the collections are equal to null.
  • Check for reference equality:
    • If the given variables reference the same object on the heap then they must be equal.
  • Check that the collections are of the same size:
    • If the collections differ in size then they cannot possibly be equal.

Additional Tidbit: C# differs from VB in that should you compare two objects of a reference type that do not overload the == operator, the runtime will default to reference equality. This means that in C# you can compare two collections using the == operator without a compile-time error but despite avoiding the compile-time error, you will probably find yourself with a logic error. Reference equality means that the object variables that are compared refer to the same object on the managed heap – this is not the same as checking if the given collections contain the same sequence of elements.

How To Identify Duplicate Elements In a Collection:
Removing duplicate elements from a given collection is easy enough, simply call the Enumerable.Distinct method on your collection. But how do actually identify which elements appear in the collection more than once? That is, how do you identify which elements in the given collection are duplicates?

The solution that I propose is a simple one. Enumerate the given collection, grouping each element by a key value. Once each element in the given collection has been grouped, filter the collection of groups by groups that contain more than one element. Groups that contain more than one element are groups whose key values are duplicates in the original collection.

If you already understand the concept of grouping, the solution I propose is really quite simple. For those of you who do not understand the concept of grouping, I can appreciate that the given overview will not be very helpful. In an attempt to improve your understanding I prepared an information graphic.

Code:
dim someCollection  = New String(){ "foo", "foo", "bar" }

Dim duplicates =
    someCollection.GroupBy(Function(element) element) _
    .Where(Function(grouping) grouping.Count() > 1) _
    .Select(Function(grouping) grouping.Key)

How To Generate "Pastel" Colors
Should you ever find the need to generate random colors that do not clash and compliment each other nicely, then you may find the following helper class to be of use. Pastel colors are said to be colors "of a soft and delicate shade or color" and in my opinion, most pastel colors compliment each other quite nicely:



I think that this helper class will be of the most use to those of you who are working on user-drawn controls, especially chart controls and the like. For example, if you are working on a pie chart control, it could be nice to present segments of the pie chart in random pastel colours to the user.

Code:
Public Class PastelColorGenerator

    private ReadOnly random as Random = New Random()

    public Function  GenerateBrush() As Brush
        Return New SolidBrush(GenerateColor())
    End Function

    public Function GenerateColor() As Color
        Dim rgbColor(3) As Byte 

        rgbColor(0) = CByte((random.Next(128 + 1) + 127))
        rgbColor(1) = CByte((random.Next(128 + 1) + 127))
        rgbColor(2) = CByte((random.Next(128 + 1) + 127))
        
        Return Color.FromArgb(rgbColor(0), rgbColor(1), rgbColor(2))
    End Function

End Class

The function works by generating a random dark color and then effectively increasing the brightness of said color before returning to the caller. In order to generate the initial dark color, the function generates thee random numbers (RGB) between 0 and 128. Given that the maximum applicable value for any of these three numbers is 255, this makes for an inherently dark color. Once the initial dark color has been generated, each of the three RGB values used to form the initial dark colour are incremented by 128.

In order to materialize the concept, consider the following visualization where the dark color is displayed on the left and the pastel color is presented on the right:

This post was last modified: 11-17-2014, 05:46 PM by Null.


Thread Closed 


Forum Jump:


Possibly Related Threads...
Thread Author Replies Views Last Post
   Basic Generic Publisher/Subscriber Implementation AceInfinity 0 385 11-19-2017, 01:56 AM
Last Post: AceInfinity
   Visual Basic Beginners Course- Signup Thread [OPEN] AceInfinity 113 55,349 05-10-2017, 12:04 AM
Last Post: ctthuhuong
   Visual Studio Tools AceInfinity 5 2,028 10-17-2015, 06:18 PM
Last Post: AceInfinity
  Visual Studio 2015 Preview available KoBE 7 3,867 11-16-2014, 06:19 PM
Last Post: AceInfinity
  WHAT!?!? Crazy Visual Studio feature. KoBE 5 2,976 03-19-2014, 03:24 AM
Last Post: t0kneneng


Users browsing this thread: 1 Guest(s)