# Linq **Repository Path**: shencheng2/c11studyLinq ## Basic Information - **Project Name**: Linq - **Description**: 这个LINQ的实现貌似是我见过的最C++11的。 - **Primary Language**: Unknown - **License**: BSL-1.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-09-02 - **Last Updated**: 2024-09-02 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README 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: ```c# struct student_t { std::string last_name; std::vector scores; }; std::vector 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: ```c++ vector 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: ```c++ struct contains_t { template bool operator()(Range && r, T && x) const { return (r | linq::find(x)) != boost::end(r); }; }; ``` Then initialize the extension using static initialization: ```c++ range_extension contains = {}; ``` Then the extension can be used like this: ```c++ 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. ```c# struct student { std::string name; std::vector grades; student() {} template student(std::string name, Range&& r) : name(name), grades(boost::begin(r), boost::end(r)) {} }; std::vector 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. ```c# vector 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. ```c# std::vector 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. ```c# struct person { std::string name; int age; person() {} person(std::string name, int age) : name(name), age(age) {} }; std::vector 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. ```c# struct person { std::string name; int age; person() {} person(std::string name, int age) : name(name), age(age) {} }; std::vector 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](http://cget.readthedocs.io/en/latest/): 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](http://connect.microsoft.com/VisualStudio/feedback/details/634688) 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](LICENSE)