高阶函数找到列表的最小值

时间:2016-11-01 09:38:43

标签: r higher-order-functions

我正在循环估算并保存所有估算对象,然后选择具有最低偏差的那个。为此,我想使用Filter / Map / Position函数,但我找不到解决方案,因为它总是返回列表的第一个对象,而不是第二个。我可能误解了位置功能如何工作,但想知道我错过了什么。

MWE:

ls<-list(3,2,4)
Position(min,Map(function(x) {x^2}, ls))

我最终使用了unlist和which.min

1 个答案:

答案 0 :(得分:1)

您最终执行了正确的操作。为什么?首先,我们将从帮助页面中提取一个显着的摘录:

  

Position(f, x, right = FALSE, nomatch = NA_integer_)

     

FindPosition分别在Common Lisp的find-if和position-if之后进行模式化。如果有一个谓词函数为true的元素,则返回第一个或最后一个元素或其位置,具体取决于right分别是false(默认值)还是true。如果没有这样的元素,则返回nomatch指定的值。当前的实现未针对性能进行优化。

因此,Position()f()应用于x的所有元素以及f()的结果为TRUE时(直接或通过胁迫) Position()将返回该元素的索引(如果没有结果为TRUE,则返回分配给nomatch的值。)

这是实际的Position()函数源:

Position <- function (f, x, right=FALSE, nomatch=NA_integer_) {

  ind <- seq_along(x)
  if (right) ind <- rev(ind)

  for (i in ind) {
    if (f(x[[i]])) return(i)
  }

  nomatch

}

在源代码之后,您可以看到min()在列表的第一个元素上被调用,它返回列表位置1处向量的min()的值,该值为非-zero所以它认为它做得很好并返回它所在的列表索引。

如果你一直这样做:

Position(min, Map(function(x) {x-3}, dat))

然后你会看到结果是:

## [1] 2

并且可能认为它有效,但它只返回,因为33-3 == 0以及0列表的第一个元素被强制转换为FALSE

注意:ls也是一个基本函数的名称,因为R知道根据使用情况做什么,但是我不喜欢在函数调用中可能导致奇怪的错误常见的核心命名空间元素因此我使用了dat而不是ls

Position()背后的想法更像是:

eqls4 <- function(x) x==4

Position(eqls4, Map(function(x) {x^2}, dat))

确实返回:

## [1] 2

所以,你最终做的是100%正确。

另请注意,purrr包提供了(IMO)更易读的替代功能习惯用法+确保维护正确类型的方法,并导出%>%,因此管道也很容易获得:

library(purrr)

map(dat, ~.^2) %>% 
  flatten_dbl() %>% 
  which.min()