Linq Challenge in C++

I really love the LINQ language extension in dot net programming and I’m really glad it was added to a language I love (C#).

My background, however, has a lot of C++ in it and I still do some coding in C++ – sometimes for fun and sometimes to put back into practice things I should have know for years, but are just now being recognized by my ever-widening eyes.  A lot of that new vision comes from seeing C# and LINQ and, of course, practicing all forms of programming MOJO on programming forums, like DaniWeb.com.

One particular post I saw there was in the C++ forum, where a user posted a question about two-dimensional arrays and how to search for a particular pattern of digits based on array boundaries.  The user posted a block of digits like this:
2,2,9,8,7,3,4,
0,0,0,0,0,0,0,
3,4,5,7,8,9,6,
0,0,0,0,0,0,0,
1,3,4,5,5,5,5

The question asked was how to return a 2d array of the rows that did not contain “all” zero values.  Most programmers can imagine a series of loops and boolean settings based on boundaries to eliminate the “bad” rows.

I immediately thought “Use a WHERE clause on it”. …then I remembered I was in the C++ forum and, given the experience of the developer, might need a more traditional approach.  I gave a suggestion about looping then began to make some examples for myself – one full solution “the (traditional) hard way”, one solution in C# with LINQ and then curiosity took hold and I convinced myself it would not be “too hard” to do it with C++ (CLI) and LINQ.  I underestimated the complexity, but consider it good practice.

Here is the C# code:

using System.Collections.Generic;
using System.Linq;
//
namespace DW_409646_CS_CON
{
   class Program
   {
      public static int[,] matrix2d = new int[5, 7]
      {
         {2,2,9,8,7,3,4},
         {0,0,0,0,0,0,0},
         {3,4,5,7,8,9,6},
         {0,0,0,0,0,0,0},
         {1,3,4,5,5,5,5}
      };

      static void Main(string[] args)
      {
         List<int> lst_int = matrix2d.OfType<int>().ToList();
         //
         int intHeight = (matrix2d.GetUpperBound(0) + 1);
         int intWidth = (matrix2d.GetUpperBound(1) + 1);

         // Method one
         int[][] arr =
         (
            from i in Enumerable.Range(0, intHeight)
            let lst_intEachRow = lst_int.GetRange(i * intWidth, intWidth)
            where !lst_intEachRow.All(ix => ix.Equals(0))
            select lst_intEachRow.ToArray()
         ).ToArray();

         // Method two
         int[][] arr2 =
            Enumerable.Range(0, intHeight)
               .Select(i => lst_int.GetRange(i * intWidth, intWidth)
                  .ToArray()).Where(xa => !xa.All(ix => ix.Equals(0)))
                     .ToArray();
      }
   }
}

The C++ conversion was a little more complex, but can be done.  The tricky part was getting the return value from the Enumerable based on the height of the array:

 

   1:  #include "stdafx.h"
   2:  using namespace System;
   3:  using namespace System::Collections::Generic;
   4:  using namespace System::Linq;
   5:  //
   6:  public ref class CArrayHelper
   7:  {
   8:  public:
   9:     static array<int,2>^ matrix2d;
  10:   
  11:     CArrayHelper(array<int,2>^ matrix)
  12:     {
  13:        matrix2d = matrix;
  14:     }
  15:   
  16:     static Func<int, String^>^ intToString =
  17:        gcnew Func<int, String^>(IntToString);
  18:     
  19:     static Func<int, bool>^ isZero =
  20:        gcnew Func<int, bool>(IsZero);
  21:   
  22:     static Func<array<int>^, bool>^ notAllZeroes =
  23:        gcnew Func<array<int>^, bool>(AllZeroes);
  24:   
  25:     static Func<int, int, array<int>^>^ getArrFromArr =
  26:        gcnew Func<int, int, array<int>^>(GetArrFromArr);
  27:   
  28:     static array<array<int>^>^ OutputArrayNonZeroes()
  29:     {
  30:        return
  31:           Enumerable::ToArray
  32:              (Enumerable::Where
  33:                 (Enumerable::Select
  34:                    (Enumerable::Range(0, matrix2d->GetUpperBound(0) + 1),
  35:                       getArrFromArr), notAllZeroes));
  36:     }
  37:   
  38:  private:
  39:     static String^ IntToString(int i)
  40:     {
  41:        return i.ToString();
  42:     }
  43:   
  44:     static bool IsZero(int i)
  45:     {
  46:        return i.Equals(0);
  47:     }
  48:   
  49:     static bool AllZeroes(array<int>^ arr)
  50:     {
  51:        return !Enumerable::All<int>(arr, isZero);
  52:     }
  53:   
  54:     static array<int>^ GetArrFromArr(int i, int j)
  55:     {
  56:        return
  57:           Enumerable::ToArray(
  58:              Enumerable::ToList<int>(
  59:                 Enumerable::ToArray(
  60:                    Enumerable::OfType<int>(matrix2d)))
  61:                       ->GetRange(i * (matrix2d->GetUpperBound(1) + 1),
  62:                          (matrix2d->GetUpperBound(1) + 1)));
  63:     }
  64:  };
  65:   
  66:  void DumpIntArray(array<int>^ arr_int)
  67:  {
  68:     Console::WriteLine(
  69:        String::Join(",", 
  70:           Enumerable::ToArray(
  71:              Enumerable::Select<int>(
  72:                 Enumerable::ToArray<int>(arr_int), CArrayHelper::intToString))));
  73:  }
  74:   
  75:  int main(array<System::String ^> ^args)
  76:  {
  77:     Action<array<int>^>^ dumpIntArray = gcnew Action<array<int>^>(DumpIntArray);
  78:   
  79:     array<array<int>^>^ arrOutput = CArrayHelper(gcnew array<int,2>(5,7)
  80:     {
  81:        {2,2,9,8,7,3,4},
  82:        {0,0,0,0,0,0,0},
  83:        {3,4,5,7,8,9,6},
  84:        {0,0,0,0,0,0,0},
  85:        {1,3,4,5,5,5,5}
  86:     }).OutputArrayNonZeroes();
  87:   
  88:     Enumerable::ToList<array<int>^>(arrOutput)->ForEach(dumpIntArray);
  89:     return 0;
  90:  }
posted @ Friday, February 10, 2012 4:53 PM
Print

Comments on this entry:

# re: Linq Challenge in C++

Left by paul at 8/13/2012 9:34 AM
Gravatar
Actually using boost range library, you can do the same thing(as in C#) in standard C++. And if you prefer the query syntax, you can get pretty close to that using this linq library for C++: http://pfultz2.github.com/Linq/

Your comment:



(not displayed)

 
 
 
 

Live Comment Preview:

 
«November»
SunMonTueWedThuFriSat
2627282930311
2345678
9101112131415
16171819202122
23242526272829
30123456