【问题标题】:Why does Map only require one set of vectors as arguments, but mapply requires both that and the MoreArgs argument?为什么 Map 只需要一组向量作为参数,但 mapply 需要这和 MoreArgs 参数?
【发布时间】:2021-05-12 04:57:15
【问题描述】:

据我所知,除了简化之外,mapply 可以完成的所有事情都可以通过Map 完成。毕竟,Mapmapply 的包装器。但是,我很惊讶地看到 mapply 接受了 ... 的两个参数集(文档称之为“参数来向量化(向量或严格为正长度的列表,或全部为零长度) em>") 和所需函数 f 之上的 MoreArgs 参数,而 Map 不使用 MoreArgs,只需要 ...(文档只是将其称为“vectors") 和f

我的问题是:为什么mapply 需要MoreArgsMap 不需要? mapply 可以做一些Map 做不到的事情吗?还是mapply 试图让Map 更难的事情变得更容易?如果有,是什么?

我怀疑sapply 可能是一个有用的答案参考点。将其 XFUN... 参数与 mapply...MoreArgs 进行比较可能会有所帮助。

【问题讨论】:

标签: r functional-programming mapping apply mapply


【解决方案1】:

我们来看Map的代码:

Map
function (f, ...) 
{
    f <- match.fun(f)
    mapply(FUN = f, ..., SIMPLIFY = FALSE)
}

正如你所写,它只是一个包装器,点被转发到mapply,注意SIMPLIFY 被硬编码为FALSE

为什么mapply需要MoreArgsMap不需要?

这是一个设计选择,可能部分是由于历史原因,我不会介意明确的 MoreArgsUSE.NAMES 参数(或 SIMPLIFY = TRUE 参数),但我相信理由是Map 很简单,如果您想调整参数,建议您使用mapply。不过,您可以将MoreArgsUSE.NAMESMap 一起使用,它们将通过点传递到mapply 调用,尽管它没有记录,因为文档将... 参数描述为“向量”。

Map(sum, setNames(1:2, c("a", "b")), 1:2)
#> $a
#> [1] 2
#> 
#> $b
#> [1] 4

Map(sum, setNames(1:2, c("a", "b")), 1:2, USE.NAMES = FALSE)
#> [[1]]
#> [1] 2
#> 
#> [[2]]
#> [1] 4

Map(
  replicate, 
  2:3,
  c(FALSE, TRUE),
  MoreArgs = list(expr = quote(runif(1))))
#> [[1]]
#> [[1]][[1]]
#> [1] 0.7523955
#> 
#> [[1]][[2]]
#> [1] 0.4922519
#> 
#> 
#> [[2]]
#> [1] 0.81626690 0.07415023 0.56264388

等效的mapply 调用将是:

mapply(sum, setNames(1:2, c("a", "b")), 1:2, SIMPLIFY = FALSE)
#> $a
#> [1] 2
#> 
#> $b
#> [1] 4

mapply(sum, setNames(1:2, c("a", "b")), 1:2, USE.NAMES = FALSE, SIMPLIFY = FALSE)
#> [[1]]
#> [1] 2
#> 
#> [[2]]
#> [1] 4

mapply(
  replicate,
  2:3,
  c(FALSE, TRUE),
  MoreArgs = list(expr = quote(runif(1))))
#> [[1]]
#> [[1]][[1]]
#> [1] 0.6690229
#> 
#> [[1]][[2]]
#> [1] 0.7529774
#> 
#> 
#> [[2]]
#> [1] 0.8632736 0.7822639 0.8553680

mapply 可以做 Map 做不到的事情吗?还是 mapply 试图让使用 Map 更难的事情变得更容易?如果有,是什么?

您不能将SIMPLIFYMap 一起使用:

Map(sum, 1:3, 1:3, SIMPLIFY = TRUE)
#> Error in mapply(FUN = f, ..., SIMPLIFY = FALSE): formal argument "SIMPLIFY" matched by multiple actual arguments

一点历史

  • mapply 是在 R 1.7.0 中引入的
  • Map 是在 R 2.6 中引入的,NEWS 项目如下:

新的高阶函数 Reduce()、Filter() 和 Map()。

f 参数名称在这些函数之间共享,并且它们记录在同一页面上。我不知道为什么不使用命名函数 FUN 的原因,但是这 3 个函数(以及 ?Reduce 中记录的其他函数)之间的一致性解释了为什么 mapplyMap 不命名它们的函数参数同样的方式(一致性解释了大写M 我猜也是)。

在文档中我们也可以阅读:

Mapmapply 的简单包装器,它不尝试简化结果,类似于 Common Lisp 的 mapcar(不过,参数被回收)。未来的版本可能允许对结果类型进行一些控制。

所以,理论上,正如我从最后一句中了解到的,Map 可以升级以提供某种类型稳定性,类似于vapply 所做的。在我看来,R-devel 并没有一路走下去,因为他们想花时间正确地决定要做什么,从那时起他们就一直处于这种状态。

【讨论】:

  • 您的意思是在第二个示例中将 MoreArgs 传递给 Map 吗?很好地表明您可以将该参数传递给 Map 的 mapply,但是您还没有展示 Map 是否/如何在没有将 MoreArgs 传递给 mapply 的未记录技巧的情况下执行 mapply MoreArgs 所做的事情。该问题包含的前提是,除了简化之外, Map 不需要 MoreArgs 来完成 mapply 所做的所有事情。这个前提是假的吗?也就是说,是否需要通过 Map 使用 mapply 的 MoreArgs 才能让 Map 完成所有 mapply 可以做的事情?
  • 我确实说过“我相信 Map 的基本原理是简单的,如果你想调整参数,我们鼓励你使用 mapply”,我认为它回答了这个问题。 Map 确实是对 mapply 的包装,范围有限,您可以单独使用 Map 完成所有 Map 操作,但反之则不然。
  • 我对这些例子仍有疑问。您对Map 的第二次使用,即Map(sum, setNames(1:2, c("a", "b")), 1:2, moreArgs = 10, USE.NAMES = FALSE) 不需要MoreArgs 参数。 Map(sum, setNames(1:2, c("a", "b")), 1:2, 10, USE.NAMES = FALSE) 给出完全相同的输出,这表明Map...mapplyMoreArgs 之间的区别尚未明确。
  • 我加了一个例子
  • 谢谢。我的最后一条评论:对于编写新示例的等效方式是Map(function(x,y) replicate(x,runif(1),y),2:3,c(FALSE, TRUE)),有什么要说的吗?很明显,MoreArgs 旨在成为每次调用mapply 时使用的参数。也就是说,它们没有被 vecotrized 覆盖。这是否意味着我们可以调用MoreArgs 某种语法糖?鉴于您的回答,我试图回答Map 用户打算使用什么来代替未记录的MoreArgs 的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-01
  • 2011-02-21
  • 2015-01-17
相关资源
最近更新 更多