PHP 中的递归生成器

2024-01-13

介绍

自 PHP 5.5 版本以来,出现了以下很棒的功能发电机 http://php.net/manual/en/language.generators.overview.php。我不会重复官方手册页,但它们对于迭代器的简短定义来说是很棒的事情。最知名的样本是:

function xrange($from, $till, $step)
{
   if ($from>$till || $step<=0)
   {
      throw new InvalidArgumentException('Invalid range initializers');
   }

   for ($i = $from; $i < $till; $i += $step)
   {
      yield $i;
   }
}

//...

foreach (xrange(2, 13, 3) as $i)
{
   echo($i.PHP_EOL); // 2,5,8,11
}

而生成器实际上不是一个函数,而是一个具体类的实例:

get_class(xrange(1, 10, 1)); // Generator

问题

讲完了 RTM 的内容,现在开始讨论我的问题。想象一下我们想要创建生成器斐波那契数列 http://en.wikipedia.org/wiki/Fibonacci_number。通常,要获得这些,我们可以使用简单的函数:

function fibonacci($n)
{
   if(!is_int($n) || $n<0)
   {
      throw new InvalidArgumentException('Invalid sequence limit');
   }
   return $n < 2 ? $n : fibonacci($n-1) + fibonacci($n-2);
}

var_dump(fibonacci(6)); // 8

让我们将其转化为可以成立的东西sequence不仅是最后一个成员:

function fibonacci($n)
{
   if (!is_int($n) || $n<0)
   {
      throw new InvalidArgumentException('Invalid sequence limit');
   }
   if ($n<2)
   {
      return range(0, $n);
   }
   $n1 = fibonacci($n-1);
   $n2 = fibonacci($n-2);
   return array_merge($n1, [array_pop($n1)+array_pop($n2)]);
}

//...

foreach (fibonacci(6) as $i)
{
   echo($i.PHP_EOL); // 0,1,1,2,3,5,8
}

我们现在有一个返回完整序列数组的函数

问题

最后,问题部分:我该如何改造我最新的fibonacci函数所以它会yield我的值,不将它们保存在数组中?我的$n可能很大,所以我想利用发电机的好处,比如xrange样本。伪代码将是:

function fibonacci($n)
{
   if (!is_int($n) || $n<0)
   {
      throw new InvalidArgumentException('Invalid sequence limit');
   }

   if ($n<2)
   {
      yield $n;
   }

   yield fibonacci($n-2) + fibonacci($n-1);
}

但这显然是垃圾,因为我们不能像这样处理它,因为递归会导致类的对象Generator并不是int value.

Bonus:获取斐波那契序列只是更一般问题的示例:在常见情况下如何使用递归生成器?当然,我可以使用标准Iterator http://php.net/manual/en/class.iterator.php为此或重写我的函数以避免递归。但我想用发电机来实现这一点。这可能吗?这是否值得努力以这种方式使用?


因此,我在尝试创建递归生成器函数时遇到的问题是,一旦超过第一个深度级别,每个后续收益都会屈服于其父调用而不是迭代实现(循环)。

从 php 7 开始,添加了一个新功能,允许您产量来自随后的生成器函数。这是新的生成器委托特征:https://wiki.php.net/rfc/generator-delegation https://wiki.php.net/rfc/generator-delegation

这使我们能够从后续的递归调用中产生收益,这意味着我们现在可以使用生成器有效地编写递归函数。

$items = ['what', 'this', 'is', ['is', 'a', ['nested', 'array', ['with', 'a', 'bunch',  ['of', ['values']]]]]];

function processItems($items)
{
    foreach ($items as $value)
    {
        if (is_array($value))
        {
            yield from processItems($value);
            continue;
        }
        yield $value;
    }
}

foreach (processItems($items) as $item)
{
    echo $item . "\n";
}

这给出了以下输出..

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

PHP 中的递归生成器 的相关文章

随机推荐

  • 在 Android 中共享 URL 到 Facebook、Twitter 和电子邮件?

    Android 上有类似 getsharekit com 的东西吗 它允许将 URL 共享到社交网站 有没有类似的东西 或者我需要为 facebook Twitter 和电子邮件单独编码吗 我不知道这是否是你的意思 但你可以使用 Andro
  • 访问已创建的 Chart.js 图表

    我创建了一个带有角度图的条形图 如下所示
  • C# 中 XML 映射到没有属性的对象

    是否有 C 库允许将 C 对象映射到没有属性的 XML 我有几个数据源 它们都包含具有相同逻辑结构但不同架构的 XML 数据 例如 在一个 XML 中可能有一个名为 邮政编码 的字段 在另一个 XML 中 此数据将位于名为 邮政编码 的属性
  • org.hibernate.HibernateException:如果没有活动事务,get 无效

    我是休眠新手 自动创建 hibernate cfg xml Netbeans 向导 自动创建HibernateUtil java 自动创建带有注释的 POJO 类 尝试从数据库获取对象但出现错误 Exception in thread po
  • 使用 Paramiko 从 SSH 跳转主机加载密钥

    我使用中间主机 2 从主机 1 连接到主机 3 主机1 gt 主机2 gt 主机3 这是我的代码 运行良好 SSH to host2 ssh paramiko SSHClient ssh load system host keys ssh
  • grunt 服务:并发:服务器由于警告而中止

    突然我的项目不再与 grunt 一起工作 不幸的是 我有一段时间没有将更改提交到 git 中 所以我无法说出有什么不同 当我跑步时grunt server verbose 我得到以下输出 上面的所有内容 通过与OK Running wire
  • JPasswordField 返回一些转换为字符串类型的哈希码

    我的程序在初始化程序之前需要用户的用户名和密码验证 所以我创建了一个按钮登录 并将其与 ActionListener 关联 如下所示 login addActionListener new ActionListener public voi
  • 暂停 Nivo 滑块

    我想在 Nivo 滑块运行之前暂停 5 秒钟 但显示第一张图像 所以我需要在属性中添加一些代码afterLoad我相信 我试过了setTimout在运行滑块代码之前 它不会给出我想要的结果 这是我当前的代码 window load func
  • 是否有像 C++ STL 的“transform”这样的 Objective-C 算法?

    我的目标是拥有一个包含特定扩展名的所有文件名但不包含扩展名的数组 有一个获取特定扩展名的所有文件名的优雅解决方案 https stackoverflow com questions 499673 getting a list of file
  • 当用户未经身份验证时,如何防止 Laravel 设置会话 cookie?

    默认情况下 Laravel 在每个请求上都会设置一个名为 APP NAME session 的 Cookie 它用于以下功能redirect gt back 这个 cookie 会阻止我的缓存机制正常工作 FastCGI Varnish 凡
  • Django REST Framework - 嵌套序列化器的查询限制?

    我遇到一种情况 一个表通过外键与另一个表相关 如下所示 模型 py class Container models Model size models CharField max length 20 shape models CharFiel
  • 更改 WinForm 按钮文本颜色?

    我想知道是否可以更改 WinForm 按钮文本的颜色 我正在查看字体属性 找不到任何东西 但我觉得像这样简单且 在我看来 实用的东西应该是可能的 你需要ForeColor按钮的属性 继承自Control See 这个链接 http msdn
  • 使用谷歌表格 API

    我希望能够从 Android 应用程序编辑 Google 电子表格 我读到我需要执行 OAuth 2 0 只有之后我才能访问 API 在 android 网站的 Google 授权 REST API 中 它说 Note An OAuth 2
  • Android ViewPager2 不动态包裹不同大小片段的高度

    我有一个 ViewPager2 它具有不同高度的片段作为子项 子项的高度在数据加载后会发生变化
  • Jackson真的无法将json反序列化为泛型类型吗?

    这是一个重复的问题 因为以下问题要么很混乱 要么根本没有答案 使用 Jackson 反序列化通用类型 https stackoverflow com questions 13118798 deserializing a generic ty
  • 通过 Play 中的“activator run”运行时获取要编译的资源

    我使用 Sass 作为 CSS 预处理器 并尝试让它通过资产管道运行 我尝试将此 sassTask 实现为源文件任务和 Web 资产任务 但两种方式都遇到了问题 如果我将 Sass 作为源任务运行 见下文 它会在activator run当
  • Rails 选择助手 - 默认选择值,如何?

    这是我现在使用的一段代码 如何修改它使其默认值等于params pid 页面何时加载 这应该可以做到
  • TFS:查询包含特定变更集的构建

    我有许多基于 TFS 中的单个分支 例如 Main 执行的构建定义 我想 以某种方式 查询 TFS 以查找包含我提供的特定变更集编号的所有构建 并返回 TFS 包含的构建名称的字符串列表 任何类型的应用程序 VS 扩展 CLI 应用程序 w
  • 在Python中组合多个for循环

    比方说 我们有一个名为 articles 的变量中的对象列表 每个对象都有一个成员 tags 这是一个简单的列表 预期输出 所有文章中的所有标签 加入到一个列表中 在多行中 解决方案是 arr for article in articles
  • PHP 中的递归生成器

    介绍 自 PHP 5 5 版本以来 出现了以下很棒的功能发电机 http php net manual en language generators overview php 我不会重复官方手册页 但它们对于迭代器的简短定义来说是很棒的事情