使用C++ ranges生成唯一随机数时出现重复值问题排查
问题分析与解决
你的问题出在filter的判断逻辑完全写反了,和ranges的使用、unordered_set本身没关系。
逻辑错误拆解
std::unordered_set::emplace的返回值是一个pair:第一个是指向元素的迭代器,第二个是bool值——插入成功(元素不存在)返回true,插入失败(元素已存在)返回false。
你当前的filter条件是return !u.emplace(i).second;,意思是:
- 当元素是新的(插入成功),
emplace返回true,取反后是false,该元素会被filter丢弃 - 当元素重复(插入失败),
emplace返回false,取反后是true,该元素会被filter保留
这和你想要的“生成不重复的15个随机数”完全相反,反而会保留重复出现的元素,自然会出现0多次的情况。
修复代码
把filter的返回值改成直接返回u.emplace(i).second即可:
auto rng = std::views::iota(0) | std::views::transform([](size_t){ return rand() % 26; }) | std::views::filter([u = std::unordered_set<size_t>()](size_t i) mutable { return u.emplace(i).second; }) | std::views::take(15); for (auto&& x : rng) { std::cout << x << std::endl; }
额外提示
rand()的随机质量不高,建议用C++11引入的<random>库替代,比如std::mt19937配合std::uniform_int_distribution- 你的iota从0开始,但transform里根本没用到这个参数,可以改成
std::views::repeat(0)或者直接忽略参数,不过当前写法不影响功能
内容的提问来源于stack exchange,提问作者tomdol
相关产品推荐
相关产品推荐

