如何在需要两个参数的函数的向量上使用 std::ranges ?

2023-12-06

我一直在尝试了解新的范围库,并尝试将一些更传统的 for 循环转换为函数代码。给出的示例代码参考参数非常简单易读。但是,我不确定如何将范围应用于点向量,该点向量需要查看、计算并比较每个 x 和 y 值,并在最后比较最大距离。

struct Point
{
  double x;
  double y;
}

double ComputeDistance(const Point& p1, const Point& p2)
{
  return std::hypot(p1.x - p2.x, p1.y - p2.y);
}

double GetMaxDistance(const std::vector<Point>& points)
{
  double maxDistance = 0.0;

  for (int i = 0; i < points.size(); ++i)
  {
    for(int j = i; j < points.size(); ++j)
    {
      maxDistance = std::max(maxDistance, ComputeDistance(points.at(i),points.at(j)));
    }
  }
  return maxDistance;
}

GetMaxDistance是我想尝试清理并应用范围的代码。我认为这就像做类似的事情一样简单:

double GetMaxDistance(const std::vector<Point>& points)
{
  auto result = points | std::views::tranform(ComputeDistance);
  return static_cast<double>(result);
}

然后我意识到这是不正确的,因为我没有将任何值传递给函数。所以我认为:

double GetMaxDistance(const std::vector<Point>& points)
{
  for(auto point : points | std::views::transform(ComputeDistance)) 
    // get the max distance somehow and return it?
    // Do I add another for(auto nextPoint : points) here and drop the first item?
}

但后来我意识到我将该函数应用于每一点,但不是它旁边的点,而且这也不起作用,因为我仍然只将一个参数传递到函数中ComputeDistance。由于我需要计算向量中所有点的距离,因此我必须将每个点相互比较并进行计算。将其保留为n^2算法。我并不想打败它n^2,我只是想知道是否有一种方法可以使这种传统的 for 循环采用现代的函数式方法。

这让我们回到了标题。我该如何申请std::ranges在这种情况下?是否有可能利用标准目前给我们的东西来做?我知道 C++23 中还需要添加更多内容。所以我不知道在发布之前这是否无法实现,或者是否根本不可能做到。

Thanks!


您正在寻找的算法是组合 - 但没有范围适配器(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 不支持,但是你可以让它发挥作用.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在需要两个参数的函数的向量上使用 std::ranges ? 的相关文章

  • 进程何时获得 SIGABRT(信号 6)?

    C 中进程获得 SIGABRT 的场景有哪些 该信号是否始终来自进程内部 或者该信号可以从一个进程发送到另一个进程吗 有没有办法识别哪个进程正在发送该信号 abort 向调用进程发送SIGABRT信号 就是这样abort 基本上有效 abo
  • 我的线程图像生成应用程序如何将其数据传输到 GUI?

    Mandelbrot 生成器的缓慢多精度实现 线程化 使用 POSIX 线程 Gtk 图形用户界面 我有点失落了 这是我第一次尝试编写线程程序 我实际上并没有尝试转换它的单线程版本 只是尝试实现基本框架 到目前为止它是如何工作的简要描述 M
  • 以编程方式检查页面是否需要基于 web.config 设置进行身份验证

    我想知道是否有一种方法可以检查页面是否需要基于 web config 设置进行身份验证 基本上如果有这样的节点
  • 为什么要序列化对象需要 Serialized 属性

    根据我的理解 SerializedAttribute 不提供编译时检查 因为它都是在运行时完成的 如果是这样 那么为什么需要将类标记为可序列化呢 难道序列化器不能尝试序列化一个对象然后失败吗 这不就是它现在所做的吗 当某些东西被标记时 它会
  • Clang 编译器 (x86):80 位长双精度

    我正在尝试在 x86 Windows 平台上使用本机 80 位长双精度 海湾合作委员会选项 mlong double 80 https gcc gnu org onlinedocs gcc x86 Options html似乎不适用于 cl
  • 从多个类访问串行端口

    我正在尝试使用串行端口在 arduino 和 C 程序之间进行通信 我对 C 编程有点陌生 该程序有多种用户控制形式 每一个都需要访问串口来发送数据 我需要做的就是从每个类的主窗体中写入串行端口 我了解如何设置和写入串行端口 这是我的 Fo
  • ASP MVC:服务应该返回 IQueryable 的吗?

    你怎么认为 你的 DAO 应该返回一个 IQueryable 以便在你的控制器中使用它吗 不 您的控制器根本不应该处理任何复杂的逻辑 保持苗条身材 模型 而不是 DAO 应该将控制器返回给视图所需的所有内容 我认为在控制器类中看到查询 甚至
  • 如何从网站下载 .EXE 文件?

    我正在编写一个应用程序 需要从网站下载 exe 文件 我正在使用 Visual Studio Express 2008 我正在使用以下代码 private void button1 Click object sender EventArgs
  • 即使手动设置显示环境变量后,WSL Ubuntu 也会显示“错误:无法打开显示”

    我在 WSL Ubuntu 上使用 g 我使用 git 克隆了 GLFW 存储库 使用了ccmake命令配置并生成二进制文件 然后使用make在 build 目录中最终创建 a文件 我安装了所有OpenGL相关的库 usr ld 我不记得我
  • 在 2D 中将一个点旋转另一个点

    我想知道当一个点相对于另一个点旋转一定角度时如何计算出新的坐标 我有一个块箭头 想要将其相对于箭头底部中间的点旋转角度 theta 这是允许我在两个屏幕控件之间绘制多边形所必需的 我无法使用和旋转图像 从我到目前为止所考虑的情况来看 使问题
  • 生产代码中的 LRU 实现

    我有一些 C 代码 需要使用 LRU 技术实现缓存替换 目前我知道两种实现LRU缓存替换的方法 每次访问缓存数据时使用时间戳 最后比较替换时的时间戳 使用缓存项的堆栈 如果最近访问过它们 则将它们移动到顶部 因此最后底部将包含 LRU 候选
  • 将构建日期放入“关于”框中

    我有一个带有 关于 框的 C WinForms 应用程序 我使用以下方法将版本号放入 关于 框中 FileVersionInfo GetVersionInfo Assembly GetExecutingAssembly Location F
  • 当“int”处于最大值并使用 postfix ++ 进行测试时,代码定义良好吗?

    示例 未定义行为的一个示例是整数溢出的行为 C11dr 3 4 3 3 int溢出是未定义的行为 但这是否适用于存在循环的以下内容 并且不使用现在超出范围的副作用i 特别是 这是否后缀增量规格帮助 结果的值计算在副作用之前排序 更新操作数的
  • 在 C 中使用 GNU automake 中的解析器

    我是 GNU autotools 的新手 在我的项目中使用了 lex 和 yacc 解析器 将它们作为 makefile am 中的源代码会产生以下错误 配置 in AC CHECK PROGS YACC bison yacc none i
  • 当我“绘制”线条时,如何将点平均分配到 LineRenderer 的宽度曲线?

    我正在使用线条渲染器创建一个 绘图 应用程序 现在我尝试使用线条渲染器上的宽度曲线启用笔压 问题在于 AnimationCurve 的 时间 值 水平轴 从 0 标准化为 1 因此我不能在每次添加位置时都在其末尾添加一个值 除非有一个我不知
  • 将代码拆分为标头/源文件

    我从 Asio 的示例页面中获取了以下代码 class tcp connection public boost enable shared from this
  • 什么是 __declspec 以及何时需要使用它?

    我见过这样的例子 declspec在我正在阅读的代码中 它是什么 我什么时候需要使用这个构造 这是 Microsoft 对 C 语言的特定扩展 它允许您使用存储类信息来赋予类型或函数属性 文档 declspec C https learn
  • Googletest:如何异步运行测试?

    考虑到一个包含数千个测试的大型项目 其中一些测试需要几分钟才能完成 如果按顺序执行 整套测试需要一个多小时才能完成 通过并行执行测试可以减少测试时间 据我所知 没有办法直接从 googletest mock 做到这一点 就像 async选项
  • 是否可以在 C# 中强制接口实现为虚拟?

    我今天遇到了一个问题 试图重写尚未声明为虚拟的接口方法的实现 在这种情况下 我无法更改接口或基本实现 而必须尝试其他方法 但我想知道是否有一种方法可以强制类使用虚拟方法实现接口 Example interface IBuilder
  • 错误:无效使用不完整类型“类 Move”/未定义对 Move::NONE 的引用

    拜托 我不知道为什么这个简单的代码被拒绝 它给了我 2 个编译错误 请帮帮我 I use 代码 块 20 03 我的编译器是GNU GCC 移动 hpp class Move public Move Move int int public

随机推荐

  • 通过将图像高度设置为容器高度来使图像适合其容器

    假设我有container a 它有一定的高度 以像素为单位 假设我在container a中有另一个container b 它是container a的80 现在假设我想将具有一定高度 以像素为单位 的图像放入容器中 b 如何使图像与co
  • 即使在 FormsAuthentication.SignOut() 之后 User.IsOnline = true

    我已在 web config 中设置 UserIsOnlineTimeWindow 2 然后我的 logout 函数已修改为 public ActionResult LogOff MembershipUser usr Membership
  • 使用D3,语义缩放可以应用于径向树吗?

    我用的是D3节点链接树 并且我在尝试对其应用语义缩放时遇到困难 我已经花了一些时间大惊小怪 试图让它发挥作用 所以我想我会在这里问 在我花更多时间之前看看它是否可能 我不确定语义缩放是否是线性的 仅此而已 编辑 工作解决方案 这是我的工作解
  • 如何使用 HttpURLConnection 在 Java 中等待 Expect 100-Continue 响应

    I am stuck使用 HttpURLConnection 向 Web 服务器发出 PUT http 请求 我有一些代码可以很好地发出 PUT 请求 并且我可以在标头中简单地包含 期望 100 继续请求属性 但是尽我所能尝试 我似乎无法让
  • Python:如果包含/不包含顺序相同,则从列表中删除子列表

    有没有办法从列表列表中删除重复的子列表 即使它们的顺序不同 那么我可以做类似 make 的事情吗 x 1 2 3 4 5 6 2 1 7 8 into x 1 2 3 4 5 6 7 8 是否有 itertools 函数或带有 for 循环
  • Swift 中优雅的“有界”方法

    我正在寻找一种更优雅的方法来为数字创建有界限制器 主要用于设置器 有很多技术可以确定一个值是否在界限内 但我没有看到任何本机函数来强制传入值符合这些界限 接受的答案here很接近 但我想限制这些值 而不是仅仅强制执行它们 这是我到目前为止所
  • 新的 GHC 功能——是我想象的吗?

    我发誓我在最近的一组 GHC 发行说明中看到了一个新功能 但现在我找不到任何参考资料 是我的错觉 还是这个功能真的存在 这是与加载不完整的模块有关 据我所知 它允许您关闭由于未定义变量而导致的编译错误 当然 在运行时 如果您尝试实际执行 这
  • 自调用函数 javascript

    我在 Firefox 和 Chrome 中编写了一个自调用函数 但它不会调用 我写了一些东西 大意是 function alert THE 自调用函数在当前浏览器中不起作用吗 我确实包含了页面上所有必要的标签和所有其他代码 自调用函数 实际
  • 如何递归地遍历 PyGtk 中的所有 Gtk 子项?

    我想获得主窗口的所有 Gtk 子对象的递归列表pygtk 我怎么做 注意这些 Python GTK 小部件名称 Python 递归和返回语句 这是一个函数 它是 PHP 函数的一个端口按名称获取后代 子 小部件 PHP GTK 社区 htt
  • Jboss 5,类加载器和多个类实例

    我的申请有问题 为了恢复这个问题 我必须将应用程序从 jboss 4 迁移到 jboss 5 在战争部署过程中 我遇到了这样的错误 java lang LinkageError loader constraint violation whe
  • 如何在 CUDA 中(有效地)打包位?

    我有一个字节数组 其中每个字节都是 0 或 1 现在我想将这些值打包成位 以便 8 个原始字节占用 1 个目标字节 原始字节 0 进入位 0 字节 1 进入位 1 ETC 到目前为止 我在内核中有以下内容 const uint16 t ti
  • pandas 数据帧计数唯一列表

    如果数据框中列的类型是int float or string 我们可以得到它的独特值columnName unique 但是 如果此列是一个列表 例如 1 2 3 我怎样才能得到unique本专栏的 我认为你可以将值转换为元组 然后uniq
  • Twitter 登录失败

    当我在我的android应用程序中使用twitter登录时 我遇到了一些问题 错误日志如下 09 05 15 38 48 492 22119 22119 sg com conversant swiftlive E Twitter Faile
  • 获取压缩文件的 mime 类型

    获取上传文件的 mime 类型非常简单 echo mime content type fileatt tmp name 但是 我还想检查压缩文件中包含的文件的 mime 类型 解压我的文件后 循环遍历 zip 中的文件以及位置 i是当前文件
  • 哪种方法性能更好:.Any() 与 .Count() > 0?

    in the System Linq命名空间 我们现在可以扩展我们的IE可枚举拥有Any and Count 扩展方法 最近有人告诉我 如果我想检查一个集合中是否包含 1 个或多个项目 我应该使用 Any 扩展方法而不是 Count gt
  • 如何在 JEST 测试用例中检查全局获取的响应

    因此 我使用 jest 来测试我的节点函数 该函数调用 fetch APi 来获取数据 现在当我为其编写测试用例时 我收到如下错误 expect received resolves toEqual Matcher error receive
  • 安装 Crashlytics 时出错 - SSL 对等握手失败 [已关闭]

    Closed 这个问题是无法重现或由拼写错误引起 目前不接受答案 在尝试安装 Crashlytics 时 我收到此错误 安装 Crashlytics 3 7 2 usr bin curl f L o gt var folders 7x kp
  • std::sort 具有相等的元素会导致分段错误

    我有一个存储指针的容器 我试图根据指针指向的相应对象中的数据成员以非递增顺序对这些指针进行排序 就我而言 许 多对象可能具有相同的该数据成员值 下面是一段简短的代码来说明问题 对排序函数的调用给出了分段错误 奇怪的是 如果容器中有 16 个
  • WPF 组合框的 IsEditable 属性

    我在很多地方都读到 WPF 组合不支持自动完成 但我使用 IsEditable 属性并发现自动完成功能在 WPF 4 中工作 这是新添加的吗 不 不是 是否可编辑自 NET Framework 3 0 以来就已存在 自动完成通常意味着显示选
  • 如何在需要两个参数的函数的向量上使用 std::ranges ?

    我一直在尝试了解新的范围库 并尝试将一些更传统的 for 循环转换为函数代码 给出的示例代码参考参数非常简单易读 但是 我不确定如何将范围应用于点向量 该点向量需要查看 计算并比较每个 x 和 y 值 并在最后比较最大距离 struct P