您正在寻找的算法是组合 - 但没有范围适配器(C++20 和 range-v3 中都没有,C++23 中也没有)。
但是,在这种情况下,我们可以使用通常称为平面地图的算法手动构造它:
inline constexpr auto flat_map = [](auto f){
return std::views::transform(f) | std::views::join;
};
我们可以使用如下:
double GetMaxDistance(const std::vector<Point>& points)
{
namespace rv = std::views;
return std::ranges::max(
rv::iota(0u, points.size())
| flat_map([&](size_t i){
return rv::iota(i+1, points.size())
| rv::transform([&](size_t j){
return ComputeDistance(points[i], points[j]);
});
}));
}
外层iota
是我们的第一个循环。然后对于每个i
,我们得到一个序列i+1
开始得到我们的j
。然后对于每个(i,j)
我们计算ComputeDistance
.
或者如果你想要transform
在顶层(可以说更干净):
double GetMaxDistance(const std::vector<Point>& points)
{
namespace rv = std::views;
return std::ranges::max(
rv::iota(0u, points.size())
| flat_map([&](size_t i){
return rv::iota(i+1, points.size())
| rv::transform([&](size_t j){
return std::pair(i, j);
});
})
| rv::transform([&](auto p){
return ComputeDistance(points[p.first], points[p.second]);
}));
}
甚至(这个版本产生一系列对的引用Point
,让更直接的transform
):
double GetMaxDistance(const std::vector<Point>& points)
{
namespace rv = std::views;
namespace hof = boost::hof;
return std::ranges::max(
rv::iota(0u, points.size())
| flat_map([&](size_t i){
return rv::iota(i+1, points.size())
| rv::transform([&](size_t j){
return std::make_pair(
std::ref(points[i]),
std::ref(points[j]));
});
})
| rv::transform(hof::unpack(ComputeDistance)));
}
这些基本上都做同样的事情,只是在哪里以及如何进行的问题ComputeDistance
函数被调用。
C++23将添加cartesian_product
and chunk
(range-v3 现在有它们),并且最近刚刚添加zip_transform
,这也将允许:
double GetMaxDistance(const std::vector<Point>& points)
{
namespace rv = std::views;
namespace hof = boost::hof;
return std::ranges::max(
rv::zip_transform(
rv::drop,
rv::cartesian_product(points, points)
| rv::chunk(points.size()),
rv::iota(1))
| rv::join
| rv::transform(hof::unpack(ComputeDistance))
);
}
cartesian_product
本身会给你所有对 - 其中都包括(x, x)
对全部x
以及两者(x, y)
and (y, x)
,这两者都不是你想要的。当我们把它分块时points.size()
(产生N
长度范围N
),然后我们反复丢弃一个稳定增加的(iota(1)
)元素的数量...所以只有第一个块中的一个(包含第一个元素两次的对),然后是第二个块中的两个((points[1], points[0])
and (points[1], points[1])
元素)等
The zip_transform
部分仍然产生一系列的块对Point
, the join
将其简化为一系列对Point
,然后我们需要unpack
into ComputeDistance
.
这一切都存在于 range-v3 中(除了zip_transform
有一个名为zip_with
)。但在 range-v3 中,你会得到common_tuple
,Boost.HOF 不支持,但是你可以让它发挥作用.