Giter Site home page Giter Site logo

linq's Introduction

Linq

Linq for list comprehension in C++, provides an implementation of linq for C++. Currently it only supports C++ ranges, but it does support both the extension and query methods for linq. Here's an example:

struct student_t
{
    std::string last_name;
    std::vector<int> scores;
};

std::vector<student_t> students = 
{
    {"Omelchenko", {97, 72, 81, 60}},
    {"O'Donnell", {75, 84, 91, 39}},
    {"Mortensen", {88, 94, 65, 85}},
    {"Garcia", {97, 89, 85, 82}},
    {"Beebe", {35, 72, 91, 70}} 
};

auto scores = LINQ(from(student, students) 
                   from(score, student.scores) 
                   where(score > 90) 
                   select(std::make_pair(student.last_name, score)));

for (auto x : scores)
{
    printf("%s score: %i\n", x.first.c_str(), x.second);
}

The C++ code above will outputs this(yes that is C++ code above):

Omelchenko score: 97
O'Donnell score: 91
Mortensen score: 94
Garcia score: 97
Beebe score: 91

Extension

Extensions are implemented using the | pipe operator. This allows them to be applied to any range, without requiring inherting from some special base class. So extensions can work like this:

vector<int> numbers = { 1, 2, 3, 4, 5, 6, 7, 8 };
auto r = numbers 
        | linq::where([](int x) { return x > 2; }) 
        | linq::select([](int x) { return x * x; });

The extension methods supported are:

  • aggregate(reducer)
  • aggregate(seed, reducer)
  • aggregate(seed, reducer, selector)
  • all(predicate)
  • any(predicate)
  • average()
  • concat(range)
  • contains(element)
  • count()
  • count(predicat)
  • default_if_empty()
  • default_if_empty(default_value)
  • distinct()
  • element_at(index)
  • except(range)
  • find(element)
  • first()
  • first(predicate, value)
  • first_or_default()
  • first_or_default(predicate)
  • group_by(key_selector)
  • group_by(key_selector, element_selector)
  • group_join(range, outer_key_selector, inner_key_selector, result_selector)
  • intersect(range)
  • join(range, outer_key_selector, inner_key_selector, result_selector)
  • keys()
  • last()
  • last(predicate, value)
  • last_or_default()
  • last_or_default(predicate)
  • max()
  • min()
  • order_by(selector)
  • order_by_descending(selector)
  • reverse()
  • select(selector)
  • select_many(selector)
  • sequence_equal(range)
  • single()
  • single_or_default()
  • skip(count)
  • skip_while(predicate)
  • sum()
  • take(count)
  • take_while(predicate)
  • then_by(selector)
  • then_by_descending(selector)
  • to_container()
  • union(range)
  • values()
  • where(predicate)
  • zip(range)
  • zip(range, selector)

The library also provides a range_extension class, that can be used to write your own extensions, as well. First just define the function as a function object class, like this:

struct contains_t
{
    template<class Range, class T>
    bool operator()(Range && r, T && x) const
    { return (r | linq::find(x)) != boost::end(r); };
};

Then initialize the extension using static initialization:

range_extension<contains_t> contains = {};

Then the extension can be used like this:

if (numbers | contains(5)) printf("We have a 5");

Query

from

All linq queries must start with a from statement. This specifies the variable name to be used for the lambdas and the container that the queries will be applied to. Also, multiple from statements can be used.

struct student
{
    std::string name;
    std::vector<int> grades;

    student() {}

    template<class Range>
    student(std::string name, Range&& r)
    : name(name), grades(boost::begin(r), boost::end(r))
    {}
};

std::vector<student> students =
{
    student("Bob", { 90, 100, 75 })
    student("Tom", { 92, 81, 70 })
    student("Terry", { 105, 98, 94 })
};

// { 90, 100, 75, 92, 81, 70, 105, 98, 94 }
auto q = LINQ(from(s, students) from(g, s.grades) select(g));

where

The where clause returns the element that matches the predicate. It is optional but must come after a from clause and should be before a select clause if there is one.

vector<int> v = { 1, 3, 4, 5 };
// { 1, 3, 5 }
auto q = LINQ(from(i, v) where(i % 2));

select

The select clause applies a transformation to the elements. It is optional also, but should be the very last clause.

std::vector<int> v = { 1, 2, 4 };
// { 3, 6, 24 }
auto q = LINQ(from(x, v) select(x * 3));

orderby

The orderby clause lets you specify elements to order the range by. Also ascending or descending can be preceded by the selector in order to specify the direction of ordering. The default is ascending.

struct person
{
    std::string name;
    int age;

    person() {}

    person(std::string name, int age)
    : name(name), age(age)
    {}
};

std::vector<person> people =
{
    person("Tom", 25),
    person("Bob", 22),
    person("Terry", 37),
    person("Jerry", 22)
}
//  { "Jerry", "Bob", "Tom", "Terry" }
auto q = LINQ(from(p, people) orderby(p.age, descending p.name) select(p.name));

group

The group clause groups the elements of a sequence. The first parameter is the key selector, and the second one is the value selector.

struct person
{
    std::string name;
    int age;

    person() {}

    person(std::string name, int age)
    : name(name), age(age)
    {}
};

std::vector<person> people =
{
    person("Tom", 25),
    person("Bob", 22),
    person("Terry", 37),
    person("Jerry", 22)
}
auto q = LINQ(from(p, people) group(p.age, p.name));

Installation

Linq can be easily installed with cget:

cget install pfultz2/Linq

This will install the boost dependency automatically. The library can also be installed manually with cmake.

find_package(Linq) is also available to consume Linq from cmake:

find_package(Linq)
target_linkq_libraries(yourLib linq::linq)

Requirements

For full support it requires clang or gcc, and boost. There is partial support for visual studio. Visual studio doesn't support the default_if_empty, group_by, group_join, join, order_by, select_many, and then_by extensions, and it doesn't support orderby, group, and nested from clauses. Perhaps some visual studio wizards could help find workarounds for msvc bugs.

Limitations

Multiple from statements are implemented using nested lambdas. However, because of a bug in MSVC 2010, nested lambas don't work(This should be fixed in MSVC 2012, but I haven't tested it). If there is a way to implement transparent identifiers in C++, nested lambdas could be avoided.

Also, the let, and join clauses aren't supported yet. The into clause can't be supported without the help of polymorhpic lambdas.

License

BSL-1.0

linq's People

Contributors

jwakely avatar myd7349 avatar pfultz2 avatar uilianries avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

linq's Issues

Cannot use function output as initial value

This code won't compile:

#include <linq.h>
#include<vector>
using namespace linq;
std::vector<int> f()
{
std::vector<int> result;
return result;
}
int main()
{
  auto x = f() | linq::first;
}

however this one will

#include <linq.h>
#include<vector>
std::vector<int> f()
{
std::vector<int> result;
return result;
}
int main()
{
  auto output = f();
  auto x = output | linq::first;
}

The issue is that LINQ should work with function output as well as with variable collection (and it does not)

Compilation error "macro "LINQ_WHERE" requires 3 arguments, but only 1 given"

I just tried to compile hello world example and received following error
g++ -o main main.cpp -std=c++14 -I../Linq/ main.cpp:24:1: error: macro "LINQ_WHERE" requires 3 arguments, but only 1 given select(std::make_pair(student.last_name, score))); ^ main.cpp:24:1: error: macro "LINQ_SELECT" requires 3 arguments, but only 1 given

Where "main.cpp" is just copy of example from main repo page
main.cpp:

#include <stdio.h>
#include "linq.h"

struct student_t
{
    std::string last_name;
    std::vector<int> scores;
};

int main()
{

    std::vector<student_t> students = {
        {"Omelchenko", {97, 72, 81, 60}},
        {"O'Donnell", {75, 84, 91, 39}},
        {"Mortensen", {88, 94, 65, 85}},
        {"Garcia", {97, 89, 85, 82}},
        {"Beebe", {35, 72, 91, 70}} 
    };

    auto scores = LINQ(from(student, students) 
                       from(score, student.scores) 
                       where(score > 90) 
                       select(std::make_pair(student.last_name, score)));

    for (auto x : scores){
        printf("%s score: %i\n", x.first.c_str(), x.second);
    }

    return 0;
}

My compiler - gcc
gcc version 5.3.1 20160413 (Ubuntu 5.3.1-14ubuntu2)

What am I doing wrong?
PS Sorry for my poor English

Conan package

Hello,
Do you know about Conan?
Conan is modern dependency manager for C++. And will be great if your library will be available via package manager for other developers.

Here you can find example, how you can create package for the library.

If you have any questions, just ask :-)

Simplify assign return value to stl container

Hello,
the following code is simple but not working

  vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8};
  vector<string> no_ok = numbers | linq::select([](auto x){return to_string(x);});

the following code is working but not simple

  auto ret = numbers | linq::select([](auto x){return to_string(x);});
  vector<string> ok;
  ok.assign(ret.begin(), ret.end());

So, Is there any way to simplify return value assignment?
Thanks.

how to use join?

i want use join for get value from 2 vectors.
how to use it? give me example.
thankyou

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.