GVKun编程网logo

使用 Random 和 OrderBy 是否是一个好的 shuffle 算法?[关闭](random.shuffle用法)

6

对于使用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用法)

使用 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扩展方法基本上包括调用ToListToArray输入,然后使用现有的 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不是真的随机

c – random_shuffle不是真的随机

我在这样一个向量上使用random_shuffle:
#include <algorithm>vector <Card> deck;//some code to add cards to the deck hererandom_shuffle ( deck.begin(),deck.end() );

运行时,甲板的内容会混合起来,但是当我重新启动程序时,会保留这个混合顺序.

我错过了什么?如何让它真正随机?

解决方法

您需要使用 srand先播放伪随机数生成器.
#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算法 – 是否产生了没有随机生成函数的相同结果?

c – random_shuffle算法 – 是否产生了没有随机生成函数的相同结果?

如果没有为标准库中的random_shuffle算法提供随机生成器函数,如果提供相同的数据,程序的连续运行是否会生成相同的随机序列?

例如,如果

std::random_shuffle(filenames.begin(),filenames.end());

在程序的连续运行中,在目录中的同一文件名列表上执行,生成的随机序列与先前运行中的相同吗?

解决方法

25.2.11只是说元素是均匀分布的.它不能保证在幕后使用哪个RNG(除非您将其传入),因此您不能依赖任何此类行为.

为了保证相同的洗牌结果,您需要提供自己的RNG来提供这些保证,但我怀疑即使这样,如果您更新标准库,random_shuffle算法本身也可以改变效果.

c – 如何为random_shuffle编写range-v3动作?

c – 如何为random_shuffle编写range-v3动作?

使用 range-v3 library(由@EricNiebler),使得编写算法代码更加紧凑,例如这是如何生成一堆随机数:
#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动作?

解决方法

你有两个不明确的random_shuffle_function :: operator()(Rng&&)重载,你的“错误捕获”重载需要被限制为只接受那些正确的重载拒绝的参数(我们真的需要C Concepts所以我再也没有了到SFINAE约束重载):
#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()的区别

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()的区别的相关信息,请在本站查询。

本文标签: