在某些条件下随机播放列表

2023-11-22

我有一个可以轻松比较的元素列表Equals()。我必须对列表进行洗牌,但洗牌必须满足一个条件:

第 i 个元素shuffledList[i]不得等于以下位置的元素i +/- 1也不是元素i +/- 2。该清单应被视为循环;也就是说,列表中的最后一个元素后面跟着第一个元素,反之亦然。

另外,如果可能的话,我想检查一下是否可以进行随机播放。

Note:

我正在使用c#4.0。

EDIT:

根据一些回复,我会解释一下:

  • 该列表不会超过 200 个元素,因此并不真正需要良好的性能。如果需要 2 秒来计算它,这不是最好的事情,但也不是世界末日。打乱后的列表将被保存,除非真实列表发生变化,否则将使用打乱后的列表。

  • 是的,这是一种“受控”随机性,但我预计在此方法上运行的几个会返回不同的打乱列表。

  • 在尝试下面的一些回复后,我将进行进一步的编辑。

EDIT 2:

  • Sehe 的实现失败的两个示例列表(都有解决方案):

Sample1:

`List<int> list1 = new List<int>{0,1,1,1,2,2,2,3,3,3,4,4,4,5,5,6,6,6,7,7,7,7,8,8,8,8,9,9,9,9,9,10};`

可能的解决方案:

List<int> shuffledList1 = new List<int> {9,3,1,4,7,9,2,6,8,1,4,9,2,0,6,5,7,8,4,3,10,9,6,7,8,5,3,9,1,2,7,8}

样本2:

`List<int> list2 = new List<int> {0,1,1,2,2,2,3,3,4,4,4,4,5,5,5,6,6,6,7,7,7,7,8,8,8,8,8,9,9,9,9,10};`
  • 验证:我正在使用这种方法,它不是我编写的最有效也最优雅的代码,但它确实有效:

    public bool TestShuffle<T>(IEnumerable<T> input)
    {
        bool satisfied = true;
        int prev1 = 0; int prev2 = 0;
        int next1 = 0; int next2 = 0;
        int i = 0;
        while (i < input.Count() && satisfied)
        {
            prev1 = i - 1; prev2 = i - 2; next1 = i + 1; next2 = i + 2;
            if (i == 0)
            {
                prev1 = input.Count() - 1;
                prev2 = prev1 - 1;
            }
            else if (i == 1)
                prev2 = input.Count() - 1;
            if (i == (input.Count() - 1))
            {
                next1 = 0;
                next2 = 1;
            }
            if (i == (input.Count() - 2))
                next2 = 0;
            satisfied =
                    (!input.ElementAt(i).Equals(input.ElementAt(prev1)))
                && (!input.ElementAt(i).Equals(input.ElementAt(prev2)))
                && (!input.ElementAt(i).Equals(input.ElementAt(next1)))
                && (!input.ElementAt(i).Equals(input.ElementAt(next2)))
            ;
            if (satisfied == false)
                Console.WriteLine("TestShuffle fails at " + i);
            i++;
        }
        return satisfied;
    }
    

EDIT 3:

有时会失败的另一个测试输入:

List<int> list3 = new List<int>(){0,1,1,2,2,3,3,3,4,4,4,5,5,5,5,6,6,6,6,7,7,7,8,8,8,8,9,9,9,9,10,10};

优化版本

令我失望的是,我的优化函数的运行速度仅比 LINQ“直接”版本快 7 倍。未优化的 LINQ1m43s优化14.7s.

  • linux 32 位
  • Mono 2.11 (C# 4.0) 编译器-optimize+,
  • 1,000,000TESTITERATIONS
  • VERBOSE not #define-d

优化了什么:

  • 假设输入和输出为数组
  • 在输入数组上就地工作
  • “手动”分析相同值的运行,而不是使用GroupBy (using ValueRun struct)
  • 有这些ValueRun数组中的结构而不是可枚举(列表);就地排序/随机播放
  • use unsafe块和指针(没有明显区别...)
  • 使用模索引代替MAGIC林克代码
  • 通过迭代追加而不是嵌套 LINQ 生成输出。这可能是最有效的。事实上,如果我们能走捷径的话那就更好了ValueRun具有 countruns 集合的 s 是按此计数排序的,这似乎很容易做到;然而,转置索引(循环约束所需)使事情变得复杂。无论如何,通过更大的输入和许多唯一值以及一些高度重复的值,以某种方式应用此优化的收益将会更大。

这是优化版本的代码。 _可以通过移除 RNG 的种子来获得额外的速度增益;这些只是为了能够对输出进行回归测试。

[... old code removed as well ...]


原始回复(部分的)

如果我的理解是对的,那么您正在尝试设计一种洗牌方法,以防止重复项在输出中连续出现(最小交错为 2 个元素)。

这在一般情况下是无法解决的。想象一下只有相同元素的输入:)

更新:事态陷入困境

正如我在笔记中提到的,我认为我一直没有走在正确的轨道上。要么我应该调用图论(有人吗?),要么使用简单的“暴力”算法,这是埃里克的长建议。

无论如何,这样你就可以看到我一直在做什么,以及问题是什么(使随机样本能够快速看到问题):

#define OUTPUT       // to display the testcase results
#define VERIFY       // to selfcheck internals and verify results
#define SIMPLERANDOM
// #define DEBUG        // to really traces the internals
using System;
using System.Linq;
using System.Collections.Generic;

public static class Q5899274
{
    // TEST DRIVER CODE
    private const int TESTITERATIONS = 100000;
    public static int Main(string[] args)
    {
        var testcases = new [] {
            new [] {0,1,1,2,2,2,3,3,4,4,4,4,5,5,5,6,6,6,7,7,7,7,8,8,8,8,8,9,9,9,9,10},
            new [] {0,1,1,1,2,2,2,3,3,3,4,4,4,5,5,6,6,6,7,7,7,7,8,8,8,8,9,9,9,9,9,10},
            new [] { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41, 42, 42, 42, },
            new [] {1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4},
        }.AsEnumerable();

        // // creating some very random testcases
        // testcases = Enumerable.Range(0, 10000).Select(nr => Enumerable.Range(GROUPWIDTH, _seeder.Next(GROUPWIDTH, 400)).Select(el => _seeder.Next(-40, 40)).ToArray());

        foreach (var testcase in testcases)
        {
            // _seeder = new Random(45); for (int i=0; i<TESTITERATIONS; i++) // for benchmarking/regression
            {
                try
                {
                    var output = TestOptimized(testcase);
#if OUTPUT
                    Console.WriteLine("spread\t{0}", string.Join(", ", output));
#endif
#if VERIFY
                    AssertValidOutput(output);
#endif
                } catch(Exception e)
                {
                    Console.Error.WriteLine("Exception for input {0}:", string.Join(", ", testcase));
                    Console.Error.WriteLine("Sequence length {0}: {1} groups and remainder {2}", testcase.Count(), (testcase.Count()+GROUPWIDTH-1)/GROUPWIDTH, testcase.Count() % GROUPWIDTH);
                    Console.Error.WriteLine("Analysis: \n\t{0}", string.Join("\n\t", InternalAnalyzeInputRuns(testcase)));
                    Console.Error.WriteLine(e);
                }
            }
        }

        return 0;
    }

#region Algorithm Core
    const int GROUPWIDTH = 3; /* implying a minimum distance of 2
                                 (GROUPWIDTH-1) values in between duplicates
                                 must be guaranteed*/

    public static T[] TestOptimized<T>(T[] input, bool doShuffle = false)
        where T: IComparable<T>
    {
        if (input.Length==0)
            return input;

        var runs = InternalAnalyzeInputRuns(input);
#if VERIFY
        CanBeSatisfied(input.Length, runs); // throws NoValidOrderingExists if not
#endif
        var transpositions = CreateTranspositionIndex(input.Length, runs);

        int pos = 0;
        for (int run=0; run<runs.Length; run++)
            for (int i=0; i<runs[run].runlength; i++)
                input[transpositions[pos++]] = runs[run].value;

        return input;
    }

    private static ValueRun<T>[] InternalAnalyzeInputRuns<T>(T[] input)
    {
        var listOfRuns = new List<ValueRun<T>>();
        Array.Sort(input);
        ValueRun<T> current = new ValueRun<T> { value = input[0], runlength = 1 };

        for (int i=1; i<=input.Length; i++)
        {
            if (i<input.Length && input[i].Equals(current.value))
                current.runlength++;
            else
            {
                listOfRuns.Add(current);
                if (i<input.Length)
                    current = new ValueRun<T> { value = input[i], runlength = 1 };
            }
        }

#if SIMPLERANDOM
        var rng = new Random(_seeder.Next());
        listOfRuns.ForEach(run => run.tag = rng.Next()); // this shuffles them
#endif
        var runs = listOfRuns.ToArray();
        Array.Sort(runs);

        return runs;
    }

    // NOTE: suboptimal performance 
    //   * some steps can be done inline with CreateTranspositionIndex for
    //   efficiency
    private class NoValidOrderingExists : Exception { public NoValidOrderingExists(string message) : base(message) { } }
    private static bool CanBeSatisfied<T>(int length, ValueRun<T>[] runs)
    {
        int groups = (length+GROUPWIDTH-1)/GROUPWIDTH;
        int remainder = length % GROUPWIDTH;

        // elementary checks
        if (length<GROUPWIDTH)
            throw new NoValidOrderingExists(string.Format("Input sequence shorter ({0}) than single group of {1})", length, GROUPWIDTH));
        if (runs.Length<GROUPWIDTH)
            throw new NoValidOrderingExists(string.Format("Insufficient distinct values ({0}) in input sequence to fill a single group of {1})", runs.Length, GROUPWIDTH));

        int effectivewidth = Math.Min(GROUPWIDTH, length);

        // check for a direct exhaustion by repeating a single value more than the available number of groups (for the relevant groupmember if there is a remainder group)
        for (int groupmember=0; groupmember<effectivewidth; groupmember++)
        {
            int capacity = remainder==0? groups : groups -1;

            if (capacity < runs[groupmember].runlength)
                throw new NoValidOrderingExists(string.Format("Capacity exceeded on groupmember index {0} with capacity of {1} elements, (runlength {2} in run of '{3}'))",
                            groupmember, capacity, runs[groupmember].runlength, runs[groupmember].value));
        }

        // with the above, no single ValueRun should be a problem; however, due
        // to space exhaustion duplicates could end up being squeezed into the
        // 'remainder' group, which could be an incomplete group; 
        // In particular, if the smallest ValueRun (tail) has a runlength>1
        // _and_ there is an imcomplete remainder group, there is a problem
        if (runs.Last().runlength>1 && (0!=remainder))
            throw new NoValidOrderingExists("Smallest ValueRun would spill into trailing incomplete group");

        return true;
    }

    // will also verify solvability of input sequence
    private static int[] CreateTranspositionIndex<T>(int length, ValueRun<T>[] runs)
        where T: IComparable<T>
    {
        int remainder = length % GROUPWIDTH;

        int effectivewidth = Math.Min(GROUPWIDTH, length);

        var transpositions = new int[length];
        {
            int outit = 0;
            for (int groupmember=0; groupmember<effectivewidth; groupmember++)
                for (int pos=groupmember; outit<length && pos<(length-remainder) /* avoid the remainder */; pos+=GROUPWIDTH)
                    transpositions[outit++] = pos;

            while (outit<length)
            {
                transpositions[outit] = outit;
                outit += 1;
            }

#if DEBUG
            int groups = (length+GROUPWIDTH-1)/GROUPWIDTH;
            Console.WriteLine("Natural transpositions ({1} elements in {0} groups, remainder {2}): ", groups, length, remainder);
            Console.WriteLine("\t{0}", string.Join(" ", transpositions));
            var sum1 = string.Join(":", Enumerable.Range(0, length));
            var sum2 = string.Join(":", transpositions.OrderBy(i=>i));
            if (sum1!=sum2)
                throw new ArgumentException("transpositions do not cover range\n\tsum1 = " + sum1 + "\n\tsum2 = " + sum2);
#endif
        }

        return transpositions;
    }

#endregion // Algorithm Core

#region Utilities
    private struct ValueRun<T> : IComparable<ValueRun<T>>
    {
        public T value;
        public int runlength;
        public int tag;         // set to random for shuffling

        public int CompareTo(ValueRun<T> other) { var res = other.runlength.CompareTo(runlength); return 0==res? tag.CompareTo(other.tag) : res; }
        public override string ToString() { return string.Format("[{0}x {1}]", runlength, value); }
    }

    private static /*readonly*/ Random _seeder = new Random(45);
#endregion // Utilities

#region Error detection/verification
    public static void AssertValidOutput<T>(IEnumerable<T> output)
        where T:IComparable<T>
    {
        var repl = output.Concat(output.Take(GROUPWIDTH)).ToArray();

        for (int i=1; i<repl.Length; i++) 
            for (int j=Math.Max(0, i-(GROUPWIDTH-1)); j<i; j++)
                if (repl[i].Equals(repl[j]))
                    throw new ArgumentException(String.Format("Improper duplicate distance found: (#{0};#{1}) out of {2}: value is '{3}'", j, i, output.Count(), repl[j]));
    }
#endregion

}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在某些条件下随机播放列表 的相关文章

  • 如何转发声明要在 unique_ptr 的标准容器中使用的类

    在智能指针的标准容器中使用它时 是否可以避免完整的类定义可见 例如 我无法编译以下内容 include
  • 表达式访问者仅为某些 lambda 表达式调用 VisitParameter

    我希望能够使用嵌套扩展方法将 EF 中的实体投影到相应的视图模型 参见我之前的问题使用扩展方法在 EF 中投影单个实体 https stackoverflow com questions 39585427 projection of sin
  • OpenCV SVM 给出奇怪的预测结果

    我对 OpenCV 和支持向量机都很陌生 我想使用 SVM 训练具有两个标签的数据集 然后预测给定集合的标签 我当前的集合包含大约 600 行 具有相等的类分布 1 为 300 行 1 为 300 行 包含 34 列 这是我当前用于设置 O
  • Monitor.Pulse & Wait - 意外行为

    http www codeproject com Articles 28785 Thread synchronization Wait and Pulse demystified http www codeproject com Artic
  • C 链表销毁函数

    我正在尝试学习 C 和很多人一样 我对指针有点困惑 无论如何 我创建了一个递归函数来销毁我的链表 但是正如我调试的那样 当我从函数返回时 列表的头部不应该为空 所以我猜这是对指针的一些基本误解 这是函数 void destroy struc
  • 使用 LINQ 展平嵌套字典

    所以我有一本形式的字典Dictionary
  • UI 线程正在阻塞调用 COM 对象的后台线程

    我正在开发一个通过第三方 COM 库与外部设备通信的应用程序 我试图让与设备的所有通信都通过后台线程 以防止通信问题搞砸我的应用程序 并消除在 UI 线程中进行通信所引入的一些其他复杂性 问题是 每当发生导致主 UI 线程阻塞的情况 即调用
  • 为什么我收到编译错误“使用已删除的函数 'std::unique_ptr ...”

    我收到一条巨大的编译错误消息 c mingw include c 6 1 0 bits predefined ops h 123 18 error use of deleted function std unique ptr lt Tp D
  • 是否自初始化 'A a = a;'允许吗?

    此代码在运行时在复制构造函数中失败 但编译器 MSVS2008 没有发出警告 您能解释一下 最好引用标准 这段代码是否非法或什么 我理解 A a a 永远不应该写在第一位 但我正在寻找理论背景 class A public A p new
  • 使用左连接获得不适当的输出

    我正在尝试获取变体列表 并且对于每个变体都获取所有subvariants list无论子变体属于何处 特别的Test say 100 这是示例数据 Id TestId SourceSubVariantId TargetSubVariantI
  • 如何解析多态 JSON 数组?

    我有一个 JSON 格式的文件 其中包含个人用户的记录 一些用户的记录中间有一个评论字段 我只想解析顶级项目 全名 贡献者姓名 电子邮件 使用 Newtonsoft JSON 解析器 但我似乎无法让它识别单个对象 当我将整个字符串解析为一个
  • 使用信号和槽更新指针

    我对 Qt 很陌生 请帮我解决这个问题 我正在使用线程在后台执行密集操作 同时我想更新 UI 所以我使用 SIGNALS 和 SLOTS 为了更新 UI 我发出一个信号并更新 UI 让我们考虑下面的示例代码 struct sample QS
  • 解析连接字符串

    是否有标准库或代码片段可以使用这样的连接字符串获取值 string connstr DataServiceUrl http localhost foo RemoteServerConnection server http localhost
  • WCF 服务中的缓冲区大小

    我们有一个 WCF 服务 它执行某些存储过程并将结果返回给 silverlight 客户端 某些存储过程最多返回 80K 行 下面给出的是 web config 中服务的设置
  • 我的代码哪里有泄漏?

    下面是我的代码 它打开一个 XML 文件 old xml 过滤无效字符并写入另一个 XML 文件 abc xml 最后 我将再次加载 XML abc xml 当执行以下行时 出现异常 表示 xml 文件被另一个进程使用 xDoc Load
  • 如何解决 boost::multi precision::cpp_dec_float 除法错误

    除以boost multiprecision cpp dec float有某种舍入误差 如下 include
  • 调用泛型类的方法

    这是上下文 我尝试编写一个映射器来动态地将域模型对象转换为 ViewModel 对象 我遇到的问题是 当我尝试通过反射调用泛型类的方法时 出现此错误 System InvalidOperationException 无法对 Contains
  • 小数精度

    我使用小数类型进行高精度计算 货币 但我今天遇到了这个简单的划分 1 1 37 这应该再次得到 37 http www wolframalpha com input i 1 2F 281 2F37 29 http www wolframal
  • 从其对象获取结构体字段的名称和类型

    例如 我有一个类似这样的结构 struct Test int i float f char ch 10 我有一个该结构的对象 例如 Test obj 现在 我想以编程方式获取字段名称和类型obj 是否可以 顺便说一句 这是 C 你正在要求C
  • 为什么 INT64_MIN 的定义不同?为什么他们的行为不同?

    The stdint h我公司的标题是 define INT64 MIN 9223372036854775808LL 但在我项目的一些代码中 一位程序员写道 undef INT64 MIN define INT64 MIN 92233720

随机推荐

  • 如何在Silverlight 4中使用TextBox.Watermark?

    在浏览 MSDN 文档时 您可能会遇到这个宝石 TextBox Watermark 太棒了 我一直想要一种内置方法来在我的文本框上添加水印 这太棒了 让我继续在 XAML 中设置它
  • 在 matplotlib 图例中使用文本但不使用标记

    我在用真棒字体在我的图表中 每个数据点都是 FontAwesome 字体的符号 像图标一样显示 因此 在图例中 我想使用文本 FontAwesome中的符号 来描述项目 我正在使用的代码如下 from matplotlib patches
  • 污染 Ruby 对象的目的是什么?

    我知道可以将不受信任的对象标记为受污染的对象 但其根本目的是什么以及为什么我应该这样做 人们将跟踪污点作为一种安全预防措施 以确保不受信任的数据不会被错误地用于计算 交易或解释为代码 通过内置语言功能跟踪污点比通过编码约定或依赖代码审查进行
  • Bx滑块设置高度

    所以我就开始使用bxslider 然而 我在设置滑块的大小时遇到 问题 当然 它需要最大元素的高度 我认为 如何将其设置为固定高度 例如 200px 您可以添加以下 css bx wrapper bx viewport height 200
  • 大标题折叠时如何呈现不同的导航标题?

    目前 我在 ViewController 的 viewdidLoad 中使用以下代码为导航栏启用了大标题 navigationController navigationBar prefersLargeTitles true self nav
  • 在C中关闭监听的TCP套接字

    假设您有一个套接字正在侦听 TCP 端口 并且一些客户端已连接 当在 C 中发出 sock close fd 并尝试在同一端口上再次绑定时 绑定会失败 在 netstat plutnoa 上可以看到一些 TIME WAIT 状态 例如 tc
  • MATLAB MEX 无法使用 XCode 4.3 (Mac) 找到标准库

    我开始在 Mac 运行 OSX 10 7 3 Lion 上使用从 C 代码 使用 XCode 4 3 编译的 MATLAB R2012a 的 MEX 文件 我已经安装了MATLAB提供的XCode补丁它配置 MATLAB 在 XCode 4
  • 是否存在一种在 atexit 或类似方法中释放内存而不使用全局变量的方法?

    我正在用 C 开发一个项目 我需要释放分配的内存并在退出之前关闭所有打开的文件 我决定实施一个clean函数将完成所有这些事情并调用它atexit因为有很多可能的退出场景 问题是atexit不允许我使用参数设置函数 所以我无法发送到clea
  • 如何以 O(nlogn) 时间和 O(1) 空间复杂度对链表进行合并排序

    免责声明 适用于学校 据我所知 递归地分割一个链表 然后将其发送到另一个函数进行合并是 O nlogn 时间和 O n 空间 是否可以在链表上进行归并排序 时间复杂度为 O nlogn 空间复杂度为 O 1 你会怎样做呢 感谢任何帮助 PS
  • Collections.reverseOrder 如何知道返回 Comparator 时使用什么类型参数

    根据 Java API 规范 Collections reverseOrder 的签名是 public static
  • 在 Firefox 中使用小数计算宽度,但在 Webkit 中没有小数

    我在不同浏览器中使用 HTML CSS 时遇到一个奇怪的问题 Firefox 3 6 和 Webkit 浏览器 Chrome 和 Safari 我的 HTML 看起来像这样 div class ln letters a href class
  • 优化的 strcmp 实现

    发现这个函数here 这是一个实现strcmp int strcmp const char s1 const char s2 while s1 s1 s2 s1 s2 return const unsigned char s1 const
  • -[NSInputStream read:maxLength:] 抛出一个异常,说长度太大,但事实并非如此

    我用一个NSInputStream从文件中读取数据 如果它会崩溃maxLength大于 49152 当它崩溃时 有时 但不是每次 它都会给出以下消息 由于未捕获的异常 NSInvalidArgumentException 而终止应用程序 原
  • QFile::copy() 的进度条?

    我正在制作一个在 Qt 中复制文件的程序 我想知道我该如何使用QProgressBar with bool QFile copy const QString fileName const QString newName 这是否有可能copy
  • AS3 - 我可以使用 addEventListener 检测变量值的变化吗?

    是否可以使用 EventListener 监听变量并检测该变量的值何时发生变化 谢谢 如果你把它全部封装到一个类中 这很容易做到 我们将使用 getter setter 方法 setter 方法将在每次调用时调度和事件 注意 Setter
  • 无法计算 XPath 中的表达式

    我使用 XPath 来解析 URL 返回的 XML 文档 当我使用给定的输入运行代码时 它可以工作 但是当将输入作为用户输入提供时 它会抛出异常 代码 class private String generalQuery method Sys
  • 同一代码库具有不同名称的多个应用程序

    读了这篇文章 想到了同样的问题 Android 上的一个代码库 两个应用程序 我已经创建了一个应用程序testApp有类似的项目topics splash screens logos charts rules statuses and or
  • $.ajax 忽略 DELETE 请求的数据参数

    我刚刚从 jQuery 1 3 2 更新到 1 4 3 并且在发出 AJAX DELETE 请求时看到了一些新行为 由于某种原因 在我的中传递的数据data参数未发送到服务器 例如 ajax url example data id 12 t
  • 什么是 XMPP?如何在 iOS 聊天应用程序中使用它?

    我想为 iPhone 创建一个聊天客户端应用程序 我读到 XMPP 框架是最适合用于此目的的框架之一 然而 我还没有找到太多这方面的材料 只有 Google Code 上的 XMPPFramework 以及 wiki 上的详细信息 谁能解释
  • 在某些条件下随机播放列表

    我有一个可以轻松比较的元素列表Equals 我必须对列表进行洗牌 但洗牌必须满足一个条件 第 i 个元素shuffledList i 不得等于以下位置的元素i 1也不是元素i 2 该清单应被视为循环 也就是说 列表中的最后一个元素后面跟着第