0%

How to deal with adjacent element in container

看到這篇有感而發,現實中常見的問題之一,為了方便說明,把原先的問題簡化,求鄰近元素後者比前面大的數對

最初的方法

原先我只會用這種方法

1
2
3
4
5
6
7
int calc(const std::vector<int> &v)
{
int count = 0;
for (size_t i = 0; i < v.size() - 1; i++)
if (v[i + 1] > v[i]) count++;
return count;
}

利用vector來作,實在不高明

Better Solution

參考上面blog的作法

1
2
3
4
5
6
7
8
9
template <typename T>
int calc(const T& v)
{
int count = 0;
for (auto it1 = v.cbegin(), it2 = v.cend(); it1 != v.cend(); it2 = it1, ++it1)
if (it2 != v.end())
if (*it1 > *it2) count++;
return count;
}

好一點了,不限定要是vector,不過還是要思考一下it1和it2的關聯性

Range-V3 Solution

可能成為下一代STL的Range-v3,其作法就類似FP中的pipeline的方式處理,隱藏了iterator的存在

1
2
3
4
5
6
7
template <typename T>
int calc(const T& v)
{
using namespace ranges;
auto larger = [](auto front, auto back) { return front > back; };
return distance(v | view::adjacent_remove_if(larger)) - 1;
}

Range-V3 Solution Ver 2, Sliding Window

Range-v3最近加入了Sliding Window的觀念,比起上面的方式更加通用,不過還是不知道怎麼把他轉成Ranges轉成Tuple,只好寫成這樣

1
2
3
4
5
6
7
8
9
10
11
template <typename T>
int calc(const T& v)
{
using namespace ranges;
return count_if(v | view::sliding(2), [](const auto &v) {
auto begin = ranges::begin(v);
auto front = *begin++;
auto back = *begin++;
return front < back;
});
}

Conclusion

抽象的程度越高,Debug的難度也自然越高,看著gcc或是clang吐出來的compilation error真是一個頭兩個大,尤其是跟Range-v3扯上關係

Reference

range-v3
Super expressive code by Raising Levels of Abstraction
Ranges: the STL to the Next Level