对于使用Random和OrderBy是否是一个好的shuffle算法?[关闭]感兴趣的读者,本文将提供您所需要的所有信息,我们将详细讲解random.shuffle用法,并且为您提供关于c–rando
对于使用 Random 和 OrderBy 是否是一个好的 shuffle 算法?[关闭]感兴趣的读者,本文将提供您所需要的所有信息,我们将详细讲解random.shuffle用法,并且为您提供关于c – random_shuffle不是真的随机、c – random_shuffle算法 – 是否产生了没有随机生成函数的相同结果?、c – 如何为random_shuffle编写range-v3动作?、numpy.random.shuffle()与numpy.random.permutation()的区别的宝贵知识。
本文目录一览:- 使用 Random 和 OrderBy 是否是一个好的 shuffle 算法?[关闭](random.shuffle用法)
- c – random_shuffle不是真的随机
- c – random_shuffle算法 – 是否产生了没有随机生成函数的相同结果?
- c – 如何为random_shuffle编写range-v3动作?
- numpy.random.shuffle()与numpy.random.permutation()的区别
使用 Random 和 OrderBy 是否是一个好的 shuffle 算法?[关闭](random.shuffle用法)
我在CodingHorror阅读了一篇关于各种
shuffle 算法的文章。我已经看到人们在某处这样做是为了对列表进行洗牌:
var r = new Random();var shuffled = ordered.OrderBy(x => r.Next());
这是一个好的洗牌算法吗?它是如何工作的?这是一种可接受的方式吗?
答案1
小编典典这不是我喜欢的洗牌方式,主要是因为它是 O(n log n) 没有充分理由,因为它很容易实现 O(n)
洗牌。问题中的代码通过基本上给每个元素一个随机(希望是唯一的!)数字来“工作”,然后根据该数字对元素进行排序。
我更喜欢 Durstenfeld 的Fisher-Yates shuffle变体,它可以交换元素。
实现一个简单的Shuffle
扩展方法基本上包括调用ToList
或ToArray
输入,然后使用现有的 Fisher-Yates
实现。(Random
作为参数传递,使生活总体上更美好。)周围有很多实现......我可能在某个地方得到了一个答案。
这种扩展方法的好处是,读者会很清楚你实际上想要做什么。
编辑:这是一个简单的实现(没有错误检查!):
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source, Random rng){ T[] elements = source.ToArray(); // Note i > 0 to avoid final pointless iteration for (int i = elements.Length-1; i > 0; i--) { // Swap element "i" with a random earlier element it (or itself) int swapIndex = rng.Next(i + 1); T tmp = elements[i]; elements[i] = elements[swapIndex]; elements[swapIndex] = tmp; } // Lazily yield (avoiding aliasing issues etc) foreach (T element in elements) { yield return element; }}
编辑:下面对性能的评论提醒我,我们实际上可以在洗牌时返回元素:
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source, Random rng){ T[] elements = source.ToArray(); for (int i = elements.Length - 1; i >= 0; i--) { // Swap element "i" with a random earlier element it (or itself) // ... except we don''t really need to swap it fully, as we can // return it immediately, and afterwards it''s irrelevant. int swapIndex = rng.Next(i + 1); yield return elements[swapIndex]; elements[swapIndex] = elements[i]; }}
这现在只会做它需要做的工作。
请注意,在这两种情况下,您都需要小心Random
使用的实例:
Random
大致同时创建两个实例将产生相同的随机数序列(以相同方式使用时)Random
不是线程安全的。
我有一篇文章Random
更详细地介绍了这些问题并提供了解决方案。
c – random_shuffle不是真的随机
#include <algorithm>vector <Card> deck;//some code to add cards to the deck hererandom_shuffle ( deck.begin(),deck.end() );
运行时,甲板的内容会混合起来,但是当我重新启动程序时,会保留这个混合顺序.
我错过了什么?如何让它真正随机?
解决方法
#include <algorithm>#include <cstdlib>...std::srand(std::time(0));vector <Card> deck;//some code to add cards to the deck hererandom_shuffle ( deck.begin(),deck.end() );
从以上链接注意:
Generally speaking,the pseudo-random number generator should only be seeded once,before any calls to rand(),and the start of the program. It should not be repeatedly seeded,or reseeded every time you wish to generate a new batch of pseudo-random numbers.
c – random_shuffle算法 – 是否产生了没有随机生成函数的相同结果?
例如,如果
std::random_shuffle(filenames.begin(),filenames.end());
在程序的连续运行中,在目录中的同一文件名列表上执行,生成的随机序列与先前运行中的相同吗?
解决方法
为了保证相同的洗牌结果,您需要提供自己的RNG来提供这些保证,但我怀疑即使这样,如果您更新标准库,random_shuffle算法本身也可以改变效果.
c – 如何为random_shuffle编写range-v3动作?
#include <range/v3/all.hpp> #include <iostream> #include <vector> int main() { using namespace ranges; auto const N = 10; std::vector<int> v; v.reserve(N); v |= action::push_back(view::iota(0,N)); random_shuffle(v); copy(v,ostream_iterator<>(std::cout,",")); }
Live Example.
但是,我更愿意使用假设的动作:: random_shuffle()来扩展管道
v |= action::push_back(view::iota(0,N)) | action::random_shuffle();
这是我尝试编写这样的动作(不幸的是,编写新的range-v3代码比使用库更加冗长)
#include <functional> // bind,placeholders::_1 namespace ranges { inline namespace v3 { /// \addtogroup group-actions /// @{ namespace action { struct random_shuffle_fn { private: friend action_access; static auto bind(random_shuffle_fn random_shuffle) RANGES_DECLTYPE_AUTO_RETURN ( std::bind(random_shuffle,std::placeholders::_1) ) template<typename Gen> static auto bind(random_shuffle_fn random_shuffle,Gen && rand) RANGES_DECLTYPE_AUTO_RETURN ( std::bind(random_shuffle,std::placeholders::_1,bind_forward<Gen>(rand)) ) public: struct ConceptImpl { template<typename Rng,typename I = range_iterator_t<Rng>> auto requires_(Rng&&) -> decltype( concepts::valid_expr( concepts::model_of<concepts::RandomAccessRange,Rng>(),concepts::is_true(Permutable<I>()) )); }; template<typename Rng> using Concept = concepts::models<ConceptImpl,Rng>; template<typename Rng,CONCEPT_REQUIRES_(Concept<Rng>())> Rng operator()(Rng && rng) const { ranges::random_shuffle(rng); return std::forward<Rng>(rng); } template<typename Rng,typename Gen,CONCEPT_REQUIRES_(Concept<Rng>())> Rng operator()(Rng && rng,Gen && rand) const { ranges::random_shuffle(rng,std::forward<Gen>(rand)); return std::forward<Rng>(rng); } #ifndef RANGES_DOXYGEN_INVOKED template<typename Rng> void operator()(Rng &&) const { CONCEPT_ASSERT_MSG(RandomAccessRange<Rng>(),"The object on which action::random_shuffle operates must be a model of the " "RandomAccessRange concept."); using I = range_iterator_t<Rng>; CONCEPT_ASSERT_MSG(Permutable<I>(),"The iterator type of the range passed to action::random_shuffle must allow its " "elements to be permuted; that is,the values must be movable and the " "iterator must be mutable."); } #endif }; /// \ingroup group-actions /// \relates sort_fn /// \sa `action` namespace { constexpr auto&& random_shuffle = static_const<action<random_shuffle_fn>>::value; } } /// @} } }
Live Example无法编译,因为某些operator()深藏在某处未找到.
据我所见,我忠实地从类似的代码中转换了上述代码,例如action :: sort().唯一的区别是random_shuffle()有两个重载(一个采用随机生成器),而所有其他动作(包括sort)都有一个重载,其额外参数的默认值(比较器,谓词,投影仪等) .这转换为上面的random_shuffle_fn的两个bind()静态成员函数,而所有其他操作只有一个bind()重载.
问题:如何为random_shuffle编写range-v3动作?
解决方法
#ifndef RANGES_DOXYGEN_INVOKED template<typename Rng,CONCEPT_REQUIRES_(!Concept<Rng>())> void operator()(Rng &&) const { CONCEPT_ASSERT_MSG(RandomAccessRange<Rng>(),"The object on which action::random_shuffle operates must be a model of the " "RandomAccessRange concept."); using I = range_iterator_t<Rng>; CONCEPT_ASSERT_MSG(Permutable<I>(),"The iterator type of the range passed to action::random_shuffle must allow its " "elements to be permuted; that is,the values must be movable and the " "iterator must be mutable."); } #endif
此外,您需要管道操作:: random_shuffle:
v |= action::push_back(view::iota(0,N)) | action::random_shuffle;
DEMO
numpy.random.shuffle()与numpy.random.permutation()的区别
参考API:https://docs.scipy.org/doc/numpy/reference/routines.random.html
1. numpy.random.shuffle()
API中关于该函数是这样描述的:
Modify a sequence in-place by shuffling its contents. This function only shuffles the array along the first axis of a multi-dimensional array. The order of sub-arrays is changed but their contents remains the same.
也就是说,numpy.random,shuffle(x)是进行原地洗牌,直接改变x的值,而无返回值。对于多维度的array来说,只对第一维进行洗牌,比如一个 $ 3 \times 3 $ 的array,只对行之间进行洗牌,而行内内容保持不变。 例子:
2. numpy.random.permutation()
API中关于该函数是这样描述的:
Randomly permute a sequence, or return a permuted range. If x is a multi-dimensional array, it is only shuffled along its first index.
也就是说,numpy.random,permutation(x)是返回一个被洗牌过的array,而x不变。对于多维度的array来说,只对第一维进行洗牌,比如一个 $ 3 \times 3 $ 的array,只对行之间进行洗牌,而行内内容保持不变。 例子:
我们今天的关于使用 Random 和 OrderBy 是否是一个好的 shuffle 算法?[关闭]和random.shuffle用法的分享已经告一段落,感谢您的关注,如果您想了解更多关于c – random_shuffle不是真的随机、c – random_shuffle算法 – 是否产生了没有随机生成函数的相同结果?、c – 如何为random_shuffle编写range-v3动作?、numpy.random.shuffle()与numpy.random.permutation()的区别的相关信息,请在本站查询。
本文标签: