LINQ for C++ with cpplinq

 

When it comes to programming languages, I literally use dozens, but when it comes down to an all other things being equal decision my go to language of choice tends to be C#.  One of the big plus sides of C# is the wonderful LINQ ( Language Integrated Query ).  LINQ makes heavy use of lambda (closures) a feature lacking until recently in C++.  Now with lambda expressions part of the C++ language LINQ for C++ is now a possibility.  It exists as a single hpp file you add to your project.

 

If you aren’t already familiar with LINQ, here is a simple example in C#.  It’s a simple scoreboard that sorts the results by name, then by score, then totals and averages all of the scores.  As you can see, it’s a very compact and clean way to access data.

 

using System;  using System.Collections.Generic;  using System.Linq;  using System.Text;  using System.Threading.Tasks;    namespace ConsoleApplication1  {      class Entry      {          public Entry(string name, int score)          {              this.name = name;               this.score = score;          }            public string name { get; set; }          public int score { get; set; }      }        class Program      {          static void Main(string[] args)          {              List<Entry> scoreEntries = new List<Entry>();              scoreEntries.Add(new Entry("mike", 42));              scoreEntries.Add(new Entry("bob", 99));              scoreEntries.Add(new Entry("doug", 99));              scoreEntries.Add(new Entry("steve", 12));                var sortedByName = scoreEntries.OrderBy(item => item.name).ToList();              Console.WriteLine("Sorted by score");              sortedByName.ForEach(item => { Console.WriteLine(item.name + " " + item.score); });                Console.WriteLine("nSorted by name");              var sortedByScore = scoreEntries.OrderBy(item => item.score).ToList();              sortedByScore.ForEach(item => { Console.WriteLine(item.name + " " + item.score); });                var totalOfScores = scoreEntries.Where(item => item.score > 0)                  .Sum(item => item.score);                var averageScore = scoreEntries.Average(item => item.score);              Console.WriteLine("nTotal of scores == " + totalOfScores + " Average Score == " + averageScore);                          }      }  }  

 

Now let’s take a look at the C++ version using cpplinq:

#include <string>  #include <list>  #include "cpplinq.hpp"  #include <iostream>      class Entry{      public:          Entry::Entry(std::string name, int score){              this->name = name;              this->score = score;          }            std::string name;          int score;  };      int main(int argc, char **argv)  {      std::list<Entry> scoreEntries;      scoreEntries.push_back(Entry("mike", 42));      scoreEntries.push_back(Entry("bob", 99));      scoreEntries.push_back(Entry("doug", 99));      scoreEntries.push_back(Entry("steve", 12));        using namespace cpplinq;            auto sortedByName = from(scoreEntries)          >> orderby_ascending([](const Entry & entry){ return entry.name;  })          >> to_vector();                auto sortedByScore = from(scoreEntries)          >> orderby_descending([](const Entry & entry){ return entry.score;  })          >> to_vector();        std::cout << "Sorted by name" << std::endl;      from(sortedByName)          >> for_each([](const Entry & entry){ std::cout << entry.name << " " << entry.score << std::endl; });        std::cout << std::endl << "Sorted by score" << std::endl;      from(sortedByScore)          >> for_each([](const Entry & entry){ std::cout << entry.name << " " << entry.score << std::endl; });        auto totalOfScores = from(scoreEntries)          >> select([](const Entry & entry){ return entry.score; })          >> sum();        auto averageScore = from(scoreEntries)          >> select([](const Entry & entry){ return entry.score; })          >> avg();        std::cout << std::endl << "Total of scores == " << totalOfScores << " average score == " << averageScore << std::endl;      return 0;  }    

 

A few obvious differences.  Cpplinq statements start with the from methods defining the type of data source to perform on.  In this case I used the default from() which takes a standard C++ STL type.  There are also from__array() and from_range() for working with arrays and iterators respectively.  Next the . (dot) operator has been replaced with the >> operator.  Of course the lambda syntax is different as well ( C++’s is much uglier ), otherwise at the end of the day, it is very similar to LINQ in both look and execution.

 

If you are new to C++ and are struggling to wrap your head around the uses for lambdas, give cpplinq a shot and you will quickly see their value!

Programming CPP


Scroll to Top