【发布时间】:2011-08-19 10:45:05
【问题描述】:
我有一个可以使用Equals() 轻松比较的元素列表。我必须洗牌,但洗牌必须满足一个条件:
第 i 个元素 shuffledList[i] 不能等于 i +/- 1 的元素,也不能等于 i +/- 2 的元素。该列表应被视为循环;也就是说,列表中的最后一个元素后面跟着第一个元素,反之亦然。
另外,如果可能的话,我想检查一下洗牌是否可能。
注意:
我使用的是 c# 4.0。
编辑:
根据一些回复,我再解释一下:
该列表不会有超过 200 个元素,因此没有真正需要好的性能。如果计算它需要 2 秒,这不是最好的事情,但也不是世界末日。打乱列表会被保存,除非真实列表发生变化,否则将使用打乱列表。
是的,这是一种“受控”随机性,但我希望在此方法上运行的多个随机数会返回不同的随机列表。
在尝试以下一些回复后,我会做进一步的修改。
编辑 2:
- Sehe 实施失败的两个示例列表(都有解决方案):
样品1:
`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; }
编辑 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};
【问题讨论】:
-
洗牌是否需要公平,即每个元素的所有目的地都同样可能?例如费雪-耶茨洗牌。
-
@Eric:这不可能是真正的公平。想象一个包含 4 或 5 个条目的输入列表。有了这些条件,如果你问我,结果顺序几乎是固定的
-
是的,仔细想想,需要一个更好的解释。你能明确说明哪些索引指的是原始列表,哪些指的是它的改组版本?
-
@sehe:即使相对顺序完全固定,条件也可以通过同样可能的循环换位来满足。
-
@sehe:我同意这个要求。