Click here to Skip to main content
Click here to Skip to main content
Alternative Tip

Cumulating values with LINQ

, 27 Jul 2012
Rate this:
Please Sign up or sign in to vote.
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

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)

About the Author

Mika Wendelius
Architect
Finland Finland
I've been a programmer since mid 80's using languages like assembler, C/C++, PL/I (mainframe environment), pascal, VB (I know, I know, no comments please) and C# and utilizing different techniques and tools.
 
However I'm specialized in databases and database modeling. Mostly I have used products like Oracle (from version 6), SQL Server (from version 4.2), DB2 and Solid Server (nowadays an IBM product).
 
For the past 10+ years my main concerns have been dealing with different business processes and how to create software to implement and improve them. At my spare time (what ever that actually means) I'm also teaching and consulting on different areas of database management, development and database oriented software design.

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Mobile
Web04 | 2.8.140721.1 | Last Updated 27 Jul 2012
Article Copyright 2012 by Mika Wendelius
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid