受到Linq的污染,我不愿意放弃它。但是,对于某些事情,我只需要使用C ++。
linq作为linq-consumer(即对我来说)的真正优势不在于表达树(操作起来很复杂),而是我可以轻松地混合和匹配各种功能。对于C ++样式的迭代器,是否存在.Where
,.Select
和.SelectMany
,.Skip
以及.Take
和.Concat
的等价物?
对于我编写的各种常用代码,这些都非常方便。
我不关心LINQ特有的,这里的关键问题是能够在更高级别表达算法,而不是C ++代码看起来像C#3.0。我希望能够表达“结果是由每个序列的前n个元素串联形成的”,然后在需要新序列的地方重用这样的表达式 - 无需手动(并贪婪地)实例化中间体。
答案 0 :(得分:8)
我正在研究(C#LINQ)类C ++头文件库。
这是:http://code.google.com/p/boolinq/
我想得到任何反馈......
更新:
以下是boolinq 2.0的新链接:https://github.com/k06a/boolinq
所有源代码都基于单个头文件 - https://github.com/k06a/boolinq/blob/master/boolinq/boolinq.h
超短:大约60种不同的操作少于800行!
答案 1 :(得分:6)
我想推荐P-Stade.Oven库供您参考。这是一个强大的增强库,用于STL范围,具有许多类似LINQ的功能,包括.Where,.Select .Skip .Take和.Concat等效。
答案 2 :(得分:4)
请参阅this Google网上论坛帖子。
vector<int> numbers = {1, 2, 3, 4, 8, 5, 9 , 24, 19, 15, 12 }
auto query =
from(numbers).
where([](int i) { return i < 15 && i > 10}).
select(fields::full_object);
我找不到更多或更少“官方”或被广泛接受的内容,但您可以尝试联系原始帖子的作者。
答案 3 :(得分:4)
我没有LINQ的具体经验,但Boost.Iterator库似乎接近你所指的。
我们的想法是拥有函数(IIUC,在LINQ中,它们采用扩展方法的形式,但这不是基础),使用迭代器和函数,将它们组合起来创建一个新的迭代器。
LINQ“Where”映射到make_filter_iterator
:
std::vector<int> vec = ...;
// An iterator skipping values less than "2":
boost::make_filter_iterator(_1 > 2, vec.begin())
LINQ“选择”地图到make_transform_iterator
:
using namespace boost::lambda;
//An iterator over strings of length corresponding to the value
//of each element in "vec"
//For example, 2 yields "**", 3 "***" and so on.
boost::make_transform_iterator(construct<std::string>('*', _1), vec.begin())
他们可以组成:
//An iterator over strings of length corresponding to the value of each element
// in "vec", excluding those less than 2
std::vector<int> vec = ...;
boost::make_transform_iterator(construct<std::string>('*', _1),
boost::make_filter_iterator(_1 > 2, vec.begin())
)
然而,这有一些烦人的事情:
make_xxx_iterator(some_functor, some_other_iterator)
返回的类型为xxx_iterator<type_of_some_functor, type_of_some_iterator>
这就是我在上面的代码中避免将make_xxx_iterator
的结果分配给变量的原因。 C ++ 0x“自动”功能将非常受欢迎。
但是,C ++迭代器仍然无法“独自”生活:它们必须成对出现才能发挥作用。所以,即使是“自动”,它仍然是满口的:
auto begin = make_transform_iterator(construct<std::string>('*', _1),
make_filter_iterator(_1 > 2, vec.begin())
);
auto end = make_transform_iterator(construct<std::string>('*', _1),
make_filter_iterator(_1 > 2, vec.end())
);
避免使用lambda会使事情变得冗长,但却易于管理:
struct MakeStringOf{
MakeStringOf(char C) : m_C(C){}
char m_C;
std::string operator()(int i){return std::string(m_C, i);}
};
struct IsGreaterThan{
IsGreaterThan(int I) : m_I(I){}
int m_I;
bool operator()(int i){return i > m_I;}
};
typedef boost::filter_iterator<
IsGreaterThan,
std::vector<int>::iterator
> filtered;
typedef boost::transform_iterator<
MakeStringOf,
filtered
> filtered_and_transformed;
filtered_and_transformed begin(
MakeStringOf('*'),
filtered(IsGreaterThan(2), vec.begin())
);
filtered_and_transformed end(
MakeStringOf('*'),
filtered(IsGreaterThan(2), vec.end())
);
(尚未)Boost.RangeEx库在这方面很有前途,因为它允许在单个范围内组合两个迭代器。类似的东西:
auto filtered_and_transformed = make_transform_range(
make_filter_range(vec, _1 > 2),
construct<std::string>('*', _1)
);
答案 4 :(得分:3)
在C ++ 11中使用Boost.Range和Linq,您可以用非常类似的方式编写Linq查询:
std::vector<int> numbers = { 1, 2, 3, 4 };
auto r = LINQ(from(x, numbers) where(x > 2) select(x * x));
for (auto x : r) printf("%i\n", x);
将输出:
9
16
答案 5 :(得分:2)
这是另一个alternative,它只是boost和stl算法的包装器,因此您可以获得这些实现的所有性能优势。
它的工作原理如下:
std::vector<int> xs;
auto count = from(xs)
.select([](int x){return x*x;})
.where([](int x){return x > 16;})
.count();
auto xs2 = from(xs)
.select([](int x){return x*x;})
.to<std::vector<int>>();
请注意,某些方法会返回空范围的代理,例如
std::vector<int> xs;
auto max = from(xs)
.select([](int x){return x*x;})
.where([](int x){return x > 16;})
.max()
.value_or(0);
答案 6 :(得分:0)
我个人不时使用cpplinq。很好无论如何,它都不会试图成为 LINQ 的完美翻译,并且会保持足够的C ++身份(如果可以的话),使其本身具有很强的实力。另外,除了标准的 C ++ 11 之外,您没有任何依赖关系。只要您能忍受,最好选择 cpplinq 。
答案 7 :(得分:0)
Abseil库有很多https://github.com/abseil/abseil-cpp/blob/master/absl/algorithm/container.h,还有很多容器函数:c_all_of
,c_any_of
,c_none_of
,c_find
,c_count
,{{ 1}},c_count_if
,c_replace_copy
,c_unique_copy
,c_min_element
,c_max_element