C++/CLI Enumerable::GroupJoin example for MSDN

Adding to the “Missing from MSDN” series of posts:

I find tremendous benefit in the Enumerable::GroupJoin method for mimicking the function of a left outer join in SQL --
the construct where the system reports back to you all “keys” and “values” even if the values (results) are null or empty.

With the regular Enumerable::Join, only the Key-Value pairs or groupings are returned when there is an associated result.
I had found a nifty way of inverting the join to retrieve non-matching results and it was of use until I discovered Enumerable::GroupJoin.

For all of my uses of Enumerable.* in C++/CLI, I always create a helper class to hold methods and the Funcs that will be used as delegates.
This helps prevent clutter and allows for easier reuse.

Keeping with the tradition of creating an examples that COULD HAVE BEEN in MSDN, please examine the code below.
I took the liberty of using IEnumerable<String^>^ instead of List<String^>^ to remove unnecessary code (well, sort of…).
I also chose to not give Magnus Hedland a pet, so the alternate benefit could be shown (a record with no result).

 
#include "stdafx.h"
using namespace System;
using namespace System::Collections::Generic;
using namespace System::Linq;
public ref class Person
{
public:
   property String^ Name;
   Person(String^ Name) { this->Name = Name; }
};
public ref class Pet
{
public:
   property String^ Name;
   property Person^ Owner;
   Pet(String^ Name, Person^ Owner) { this->Name = Name; this->Owner = Owner; }
};
public ref class CPersonPetHelper
//http://www.GeeksWithBlogs.Net/THines01
private:
   static String^ GetNameFromPerson(Person^ person) { return person->Name; }
   static String^ GetNameFromPetOwner(Pet^ pet) { return pet->Owner->Name; }
   static String^ GetPetName(Pet^ pet) { return pet->Name; }
   static Func<Pet^, String^>^ getPetName = gcnew Func<Pet^, String^>(GetPetName);
   //
   static KeyValuePair<String^, IEnumerable<String^>^> GetKvpFromOwnerAndPets(Person^ owner, IEnumerable<Pet^>^ pets)
   {
      return KeyValuePair<String^, IEnumerable<String^>^>
      (
         owner->Name,
         Enumerable::Select<Pet^, String^>(pets, getPetName)
      );
   }
   //
   static String^ GetStrFromKvpS2L2s(KeyValuePair<String^, IEnumerable<String^>^> kvp_s2L2s)
   {
      return String::Join("\n  ",
         Enumerable::Concat<String^>(
         (gcnew  array < String^ > { kvp_s2L2s.Key + ":" }), kvp_s2L2s.Value));
   }
public:
   static Func<Person^, String^>^ getNameFromPerson = gcnew Func<Person^, String^>(GetNameFromPerson);
static Func<Pet^, String^>^ getNameFromPetOwner = gcnew Func<Pet^, String^>(GetNameFromPetOwner);
static Func<Person^, IEnumerable<Pet^>^, KeyValuePair<String^, IEnumerable<String^>^>>^ getKvpFromOwnerAndPets =
      gcnew Func<Person^, IEnumerable<Pet^>^, KeyValuePair<String^, IEnumerable<String^>^>>(GetKvpFromOwnerAndPets);
static Func<KeyValuePair<String^, IEnumerable<String^>^>, String^>^ getStrFromKvpS2L2s =
      gcnew Func<KeyValuePair<String^, IEnumerable<String^>^>, String^>(GetStrFromKvpS2L2s);
};
static void GroupJoinEx()
//http://www.GeeksWithBlogs.Net/THines01
   array<Person^, 1>^ people =
   {
      gcnew Person("Hedlund, Magnus"),
      gcnew Person("Adams, Terry"),
      gcnew Person("Weiss, Charlotte")
   };

   array<Pet^, 1>^ pets =
   {
      gcnew Pet("Barley", people[1]),
      gcnew Pet("Boots", people[1]),
      gcnew Pet("Whiskers", people[2]),
      gcnew Pet("Daisy", people[1])
   };

   array<KeyValuePair<String^, IEnumerable<String^>^ >, 1>^ kvp_s2L2s =
      Enumerable::ToArray<KeyValuePair<String^, IEnumerable<String^>^>>
      (
         Enumerable::GroupJoin<Person^, Pet^, String^, KeyValuePair<String^, IEnumerable<String^>^>>
         (
            people,
            pets,
            CPersonPetHelper::getNameFromPerson,
            CPersonPetHelper::getNameFromPetOwner,
            CPersonPetHelper::getKvpFromOwnerAndPets
         )
      );

   Console::WriteLine
   (
      String::Join("\n",
         Enumerable::Select < KeyValuePair<String^, IEnumerable<String^>^>, String^ >
         (
            kvp_s2L2s,
            CPersonPetHelper::getStrFromKvpS2L2s
         ))
   );
}
posted @ Tuesday, August 25, 2015 9:38 AM
Print

Comments on this entry:

No comments posted yet.

Your comment:



(not displayed)

 
 
 
 

Live Comment Preview: