【问题标题】:R vector staying the same length after indexing within recursive functionR向量在递归函数中索引后保持相同的长度
【发布时间】:2018-03-03 00:21:04
【问题描述】:

我在 R 中编写了一个递归二分搜索函数,它在向量中找到大于给定值的最小元素:

binary_next_biggest <- function(x, vec){
  if (length(vec) == 1){
    if (x < vec[1]){
      return(vec[1])
    } else {
      return(NA)
    }
  } else {
    mid = ceiling(length(vec)/2)
    if (x < vec[mid]){
      return(binary_next_biggest(x, vec[1:mid]))
    } else {
      return(binary_next_biggest(x, vec[mid+1:length(vec)]))
    }
  }
}

我在 Python 中编写了这个完全相同的函数,没有任何问题(代码如下),但在 R 中它不起作用。

import numpy as np

def binary_next_biggest(x, arr):
    if len(arr)==1:
        if x < arr[0]:
            return arr[0]
        else:
            return None
    else:
        mid = int(np.ceil(len(arr)/2)-1)
        if x < arr[mid]:
            return binary_next_biggest(x, arr[:mid+1])
        else:
            return binary_next_biggest(x, arr[mid+1:])

通过在 RStudio 中的调试,我发现了它为什么不起作用的机制:在我上面的函数中索引向量会返回一个相同长度的向量,所以如果

vec <- 1:10

并且vec在函数内被索引,

vec[6:10]

传递给 binary_next_biggest() 的新调用的结果向量是

6 7 8 9 10 NA NA NA NA NA

我期望的地方

6 7 8 9 10

这里发生了什么?我知道我可以将它重写为一个迭代更改索引的 while 循环,但我不明白为什么向量索引在我编写的代码中会以这种方式运行。在交互式 R 控制台中,索引的行为符合预期并更改了向量长度,那么为什么它在函数中的行为会有所不同,以及为我正在尝试做的事情建立索引的合适方法是什么?

【问题讨论】:

  • 尝试(mid+1):length(vec) 而不是mid+1:length(vec)
  • 啊,做到了。现在我觉得很愚蠢,哈哈,这让我以前也有过。谢谢!
  • @AndreyShabalin 您介意发表您的评论作为答案,以便我选择它并关闭问题吗?
  • 当然,会发布一个答案。
  • 取决于您的数据是整数还是浮点数,我猜,但 findInterval(vs, DF$v)findInterval(vs, DF$v) + 1L 应该可以找到匹配的位置;然后只需DF$v[res] 即可获得价值。

标签: r performance indexing binary-search


【解决方案1】:

您进行二分搜索可能是有原因的(更复杂问题的简化示例?),但在 R 中有更简单的方法。

vec <- 1:1000
x <- 49
min(vec[which(vec > x)])
# [1] 50

即使没有订购 vec 也有效。

vec <- sample.int(1000)
min(vec[which(vec > x)])
# [1] 50

【讨论】:

  • 是的,我有一个大的排序 data.frame,我将不得不在其上执行数百万次搜索,所以我不希望哪个对我的案例足够有效。不过谢谢!
  • 也许值得用一个更接近你想要做的例子来询问。我无法想象将递归函数运行数百万次会很快。
【解决方案2】:

代码异常行为的原因是向量元素的索引错误。 mid+1:length(vec) 部分应该是 (mid+1):length(vec),因为 : 运算符是在添加之前执行的。

这里是差异的说明。

5 + 1:10
# [1]  6  7  8  9 10 11 12 13 14 15
(5+1):10
# [1]  6  7  8  9 10

【讨论】:

    猜你喜欢
    • 2015-10-02
    • 1970-01-01
    • 1970-01-01
    • 2018-06-25
    • 2022-06-17
    • 2017-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多