吃饱了撑的之实现drop函数?

本篇的灵感如题来自一个常见的函数drop(),他的用法是这样的:

vec{1, 2, 3, 4, 5}
vec1 = drop(2, vec) // vec1 = {3, 4, 5}
vec1 = drop(-1, vec) // vec1 = {1, 2, 3, 4, 5}
vec1 = drop(7, vec) // vec1 = {}

它在函数式或者动态语言里非常常见。一般实现是这样:

drop = (n, xs) => {
    if (n <= 0 || xs === [])
        return xs
    else 
        return drop(n - 1, tail(xs))
}

这里借助了tail()。如果用Python或者Go就是xs[1:](尾递归优化不在探讨范围)。

不过接下来看看C++能发挥什么?先写个效仿的函数:

//n could be negative
vector<int> drop(int n, const vector<int> &vec) {
  if (n <= 0 || vec.begin() >= vec.end()) {
    return vector<int>(vec.begin(), vec.end());
  } else {
    return drop(n - 1, vector<int>(vec.begin() + 1, vec.end()));
  }
}

代码只为说明问题,没考虑模板。这里和之前明显的区别是,C++没有现成的tail(),所以用迭代器构造了一个新的vector。

呃,既然都用迭代器了,岂不是可以改一下形参,使函数更灵活:

vector<int> drop(int n, vector<int>::iterator begin,
                 vector<int>::iterator end) {
  if (n <= 0 || begin >= end) {
    return vector<int>(begin, end);
  } else {
    return drop(n - 1, begin + 1, end);
  }
}

这样就灵活多了,可以通过迭代器drop指定的子vector。

呃 -_-!,是不是有点脱裤子放屁?既然都用迭代器了,还要啥自行车?

vector<int> vec{1, 2, 3, 4, 5};
int n = some number;
vector<int> vec1{vec.begin() + n, vec.end()};

虽然机制上梢有区别,但效果可以接受。通过一层抽象,原本复杂的操作可以用简单的迭代器规则表示。类似的例子,前篇博文也简述过。

进一步探讨,迭代器是不是像一个解空间的映射?通常,在处理信号时也会图方便将时域映射到频域——时域的卷积在频域是简单的乘法。原本需要通过流程实现的drop函数,对迭代器来说就是加减法(当然完整的操作仍需一点流程)。

最后,留个问题。抽象的价值是否就在于将问题映射到更简单的解空间?

P.S. 我在随后的博文中简述了这个问题。3-9-2018

One thought on “吃饱了撑的之实现drop函数?”

Leave a Reply

Your email address will not be published. Required fields are marked *