Fast and Simplified C#.Net Linq for C++14 and above !
- CMake (optional)
add_subdirectory(linq_directory)
# ...
# linq is an INTERFACE library (only headers)
# link with it will just give access to linq include directory
target_link_libraries(your_project linq)
- Add to your code
// only one file to include
// using cmake
#include <linq/linq.h>
// without cmake
#include "path_to_linq_include_dir/linq.h"
- min C++14
- works on Linux/Windows/Mac
- Create Enumerable
// create enumerable from any iterable container
// vector, map, etc...
std::vector<int> data{0, 1, 2, 3, 4, 5};
auto enu = linq::make_enumerable(data);
// or from iterable range
auto enu_range = linq::make_enumerable(data.begin() + 1, data.end());
// of create enumerable from existing enumerable
auto enu_filter = enu.Where([](auto &val){ return val < 3; });
// you are now ready to use them !
- Run on Enumerable
// let's run on data
// 1st method: using Each method
enu.Each([](auto &val){
// do something...
});
// 2nd method: simple for
for (auto &val : enu) {
// do something...
}
// you are now ready to combine enumerable
// with all supported operations
- Each
std::vector<int> data{0, 1, 2, 3, 4, 5};
linq::make_enumerable(data)
.Each([](auto &val)){
std::cout << val << " ";
});
// output: 0 1 2 3 4 5
- Select
struct User {
int id;
int groupId;
// other members...
};
std::vector<User> data{{0, 1}, {1, 2}, {2, 3}, {3, 4}, {4, 5}, {5, 6}};
linq::make_enumerable(data)
.Select([](auto &user) { return user.id; })
.Each([](auto &id) {
std::cout << id << " ";
});
// output: 0 1 2 3 4 5
- SelectMany
struct User {
int id;
int groupId;
// ...
};
std::vector<User> data{{0, 1}, {1, 2}, {2, 3}, {3, 4}, {4, 5}, {5, 6}};
linq::make_enumerable(data)
.Select([](auto &user) { return user.id; },
[](auto &user) { return user.groupId; })
.Each([](auto &tuple) {
std::cout << std::get<0>(tuple) << ":" << std::get<1>(tuple) << " ";
});
// output: 0:1 1:2 2:3 3:4 4:5 5:6
- Where
std::vector<int> data{0, 1, 2, 3, 4, 5};
linq::make_enumerable(data)
.Where([](auto &val){ return val > 3; })
.Each([](auto &val)){
std::cout << val << " ";
});
// output: 4 5
- OrderBy
struct User {
int id;
int groupId;
// other members...
};
std::vector<User> data{{0, 1}, {1, 1}, {2, 1}, {3, 2}, {4, 2}, {5, 2}};
linq::make_enumerable(data)
.OrderBy(linq::asc([](auto &user){ return user.groupId; }), // order by groupId asc
linq::desc([](auto &user){ return user.id; })) // then by id desc
.Each([](auto &user) {
std::cout << user.groupId << ":" << user.id << " ";
});
// output: 1:2 1:1 1:0 2:5 2:4 2:3
- GroupBy
struct User {
int id;
int groupId;
// other members...
};
std::vector<User> data{{0, 1}, {1, 1}, {2, 1}, {3, 2}, {4, 2}, {5, 2}};
linq::make_enumerable(data)
.GroupBy([](auto &user){ return user.groupId; }) // group by groupId
.Each([](auto &pair) {
// pair.first is groupId
// pair.second is user reference
std::cout << pair.first << ":" << pair.second.id << " ";
});
// possible output: 1:0 1:1 1:2 2:3 2:4 2:5
- Skip
std::vector<int> data{0, 1, 2, 3, 4, 5};
linq::make_enumerable(data)
.Skip(3)
.Each([](auto &val)){
std::cout << val << " ";
});
// output: 3 4 5
- SkipWhile
std::vector<int> data{0, 1, 2, 3, 4, 5};
linq::make_enumerable(data)
.SkipWhile([](auto &val){ return val < 3; })
.Each([](auto &val)){
std::cout << val << " ";
});
// output: 3 4 5
- Take
std::vector<int> data{0, 1, 2, 3, 4, 5};
linq::make_enumerable(data)
.Take(3)
.Each([](auto &val)){
std::cout << val << " ";
});
// output: 0 1 2
- TakeWhile
std::vector<int> data{0, 1, 2, 3, 4, 5};
linq::make_enumerable(data)
.TakeWhile([](auto &val){ return val < 3; })
.Each([](auto &val)){
std::cout << val << " ";
});
// output: 0 1 2
- First, Last
std::vector<int> data{0, 1, 2, 3, 4, 5};
auto enu = linq::make_enumerable(data);
std::cout << enu.First() << ":" << enu.Last(); // /!\ crash if empty
// output: 0:5
- FirstOrDefault, LastOrDefault
std::vector<int> data{};
auto enu = linq::make_enumerable(data);
std::cout << enu.FirstOrDefault() << ":" << enu.LastOrDefault();
// output: 0:0 (default int)
- Contains, Any, Count
std::vector<int> data{0, 1, 2, 3 , 4, 5};
auto enu = linq::make_enumerable(data);
std::cout << enu.Contains(6) << std::endl
<< enu.Any() << std::endl
<< enu.Count() << std::endl;
// output: false
// true
// 6
- Sum, Min, Max
std::vector<int> data{0, 1, 2, 3 , 4, 5};
auto enu = linq::make_enumerable(data);
std::cout << enu.Sum() << std::endl
<< enu.Min() << std::endl
<< enu.Max() << std::endl;
// output: 15
// 0
// 5
- Advanced Example
#include <iostream>
#include <vector>
#include "linq/linq.h"
int main() {
// my container
std::vector<int> container = { 1, 2, 3, 4, 5, 1, 2, 3, 4, 5 };
// create enumerable
auto enu = linq::make_enumerable(container);
// pick only value > 3
auto filter1 = enu.Where([](const auto &value) {
return value > 3;
});
for (auto v : filter1) {
std::cout << v;
}
// output: 4545
// let's cumulate filters from filter1
auto filter2 = filter1.Skip(1).Take(2);
std::cout << filter2.First() << ":" << filter2.Last();
// output: 5:4
// make complex filter and edit value in container
auto value_to_edit = 5;
enu.Where([value_to_edit](const auto &value){ return value == value_to_edit; }) // where value = captured variable
.Take(1) // pick only one
.Each([](auto &value) { value = 100; }); // set it to 100
// edited only the first encountred value in vector
std::cout << vec[4] << ":" << enu.Last();
// output: 100:5
// All filters are lazy, no overhead on creation, reusable if proxy container lives
// Stop naive run on your data, use linq for C++!
return 0;
}
$> cmake -Bbuild -DQB_BUILD_TEST=ON -H.
$> cd build && make
$> ./qb-linq-overhead && ./qb-linq-benchmark
- Concat
- Distinct, Union, Intersect