Click here to Skip to main content
15,885,278 members
Articles / Programming Languages / Visual Basic
Alternative
Tip/Trick

Cumulating values with LINQ

Rate me:
Please Sign up or sign in to vote.
0.00/5 (No votes)
27 Jul 2012CPOL1 min read 10.9K   20   1  
This is an alternative for "Cumulating values with LINQ"

Introduction

This is a 'kind of a' Visual Basic alternative to the original tip.

If you want to achieve the same functionality in VB as in the original C# tip, you would have to create a full iterator class. While it could be done, I started to wonder if it is feasible? Writing an iterator class is somewhat painful and maintaining it can also be a pain.

The problem is that Visual Basic doesn't currently have equivalent for yield return command. Visual Studio 2012 will change this but since it's not published yet it's not yet a usable solution.

So, instead of creating an iterator class I ended up to a solution where the extension methods are implented using a C# assembly which is simply referenced from the Visual Basic project. Here's a picture of the project setup.

The CumulativeHelper implemented using C# looks as following:

using System.Linq;

namespace CumulativeHelper {

   /// <summary>
   /// Class to hold the extension methods
   /// </summary>
   public static class CumulativeHelper {

      /// <summary>
      /// Builds a cumulative path based on directory names
      /// </summary>
      /// <param name="pathPart">Individual directories</param>
      /// <returns>Cumulated path</returns>
      public static System.Collections.Generic.IEnumerable<string> CumulativePath(
         this System.Collections.Generic.IEnumerable<string> pathPart) {

         System.Text.StringBuilder concatenated = new System.Text.StringBuilder();

         foreach (string part in pathPart) {
            if (concatenated.Length != 0) {
               concatenated.Append('\\');
            }
            concatenated.Append(part);
            yield return concatenated.ToString();
         }
      }

      /// <summary>
      /// Returns all string items in the collection except the last one
      /// </summary>
      /// <param name="stringItem">String items</param>
      /// <returns>Each string item</returns>
      public static System.Collections.Generic.IEnumerable<string> AllButLast(
         this System.Collections.Generic.IEnumerable<string> stringItem) {

         System.Text.StringBuilder concatenated = new System.Text.StringBuilder();

         for (int counter = 0; counter< stringItem.Count() - 1; counter++) {
            yield return stringItem.ElementAt(counter);
         }
      }

      /// <summary>
      /// Calculates a cumulative value for decimal numbers
      /// </summary>
      /// <param name="numbers">Numbers to sum</param>
      /// <returns>Cumulative sum</returns>
      public static System.Collections.Generic.IEnumerable<decimal> CumulativeSum(
         this System.Collections.Generic.IEnumerable<decimal> numbers) {

         decimal summedNumber = 0;

         foreach (decimal number in numbers) {
            summedNumber = summedNumber + number;
            yield return summedNumber;
         }
      }
   }
}

The functionality is described in the original tip.

Calling from Visual Basic

So the code above handles the LINQ iteration. The Visual Basic project has a project reference to the C# assembly so the VB code can call the functionality. The code for the Visual Basic portion looks like this

VB.NET
Imports CumulativeHelper

Module MainModule

    Sub Main()
        ' Array of test numbers
        Dim numbers As Decimal() = New Decimal() {1, 3, 5, 7, 11}

        ' Calculate and print the cumulative sum for the numbers
        System.Diagnostics.Debug.WriteLine("The cumulative sum contains the following results")
        For Each partialSum As Decimal In numbers.CumulativeSum()
            System.Diagnostics.Debug.WriteLine("   - {0}", partialSum)
        Next
        System.Diagnostics.Debug.WriteLine("The cumulative sum total is {0}", 
                                           numbers.CumulativeSum().Last())

        ' Some random path
        Dim somePath As String = "C:\Some directory\Some subdirectory\Somefile.txt"

        ' Split the path and print out each cumulated portion of the path
        System.Diagnostics.Debug.WriteLine("The path contains the following parts")
        For Each partialPath As String In somePath.Split("\").CumulativePath()
            System.Diagnostics.Debug.WriteLine("   - '{0}'", New Object() {partialPath})
        Next

        ' Some partially existing path
        Dim somePath2 As String = "C:\Windows\Some non-existent directory\Some non-existent file.txt"

        ' Split the path and print out each cumulated portion of the path
        System.Diagnostics.Debug.WriteLine("The path parts are valid as follows")
        For Each partialPath As String In somePath2.Split("\").AllButLast().CumulativePath()
            System.Diagnostics.Debug.WriteLine(
               "   - '{0}' does exist: {1}", 
               partialPath,
               System.IO.Directory.Exists(partialPath))
        Next
    End Sub
End Module

And the result from output is

The cumulative sum contains the following results
   - 1
   - 4
   - 9
   - 16
   - 27
The cumulative sum total is 27
The path contains the following parts
   - 'C:'
   - 'C:\Some directory'
   - 'C:\Some directory\Some subdirectory'
   - 'C:\Some directory\Some subdirectory\Somefile.txt'
The path parts are valid as follows
   - 'C:' does exist: True
   - 'C:\Windows' does exist: True
   - 'C:\Windows\Some non-existent directory' does exist: False

So the same results are achieved. In my opinion extending the LINQ in VB with enumerable methods, it may be much easier and clearer to use C# for the extension methods. The implementation is much smaller and more easily maintainable and I think that the C# code is quite easily understandable even with almost no experience with C# programming.

History

  • July 28, 2012: Alternative created.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
Europe Europe
Biography provided

Comments and Discussions

 
-- There are no messages in this forum --