c#通过参考费希尔·耶茨洗牌机
我试图使用Fisher-Yates算法来洗牌一堆元素。我无法通过引用传递堆栈。下面的代码给出了错误“迭代器不能有ref或out参数”。如何让算法作用于传入的实际堆栈 谢谢 代码如下c#通过参考费希尔·耶茨洗牌机,c#,algorithm,pass-by-reference,shuffle,C#,Algorithm,Pass By Reference,Shuffle,我试图使用Fisher-Yates算法来洗牌一堆元素。我无法通过引用传递堆栈。下面的代码给出了错误“迭代器不能有ref或out参数”。如何让算法作用于传入的实际堆栈 谢谢 代码如下 using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 { public static class Doshuffle { publ
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
public static class Doshuffle
{
public static IEnumerable<T> Shuffle<T>(ref Stack<T> source)
{
Random rng = new Random();
T[] elements = source.ToArray();
source.Clear();
// 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)
{
source.Push(element);
yield return element;
}
}
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
命名空间控制台应用程序1
{
公共静态类剂量
{
公共静态IEnumerable Shuffle(参考堆栈源)
{
随机rng=新随机();
T[]元素=source.ToArray();
source.Clear();
//注意i>0以避免最终无意义的迭代
对于(int i=elements.Length-1;i>0;i--)
{
//将元素“i”与随机较早的元素it(或其本身)交换
int swapIndex=rng.Next(i+1);
T tmp=元素[i];
元素[i]=元素[swapIndex];
元素[swapIndex]=tmp;
}
//惰性屈服(避免别名问题等)
foreach(元素中的T元素)
{
推送(元素);
收益-收益要素;
}
}
}
}
如何让算法作用于传递的实际堆栈
在哪
由于Stack
是一种引用类型,您不需要在此处使用ref
参数,并且您不会尝试重新分配引用本身
默认情况下,引用是按值传递的,但该值(引用)指向堆上的同一对象,换句话说,您有两个引用指向同一对象,这很好-所有操作都将在原始堆栈
对象上执行
编辑:
根据您的评论,我建议您重新设计,不要修改原始的堆栈
,这一点从一开始就很麻烦:
public static IEnumerable<T> Shuffle<T>(Stack<T> source)
{
Random rng = new Random();
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;
}
}
使用Random
时也要小心-您可能希望将其传入。在这一点上,你可以使用而不是你自己的-这是更好的重用比重新发明
最终编辑:
看起来您只是想在适当的位置洗牌堆栈
——请改用扩展方法:
public static void Shuffle<T>(this Stack<T> source)
{
Random rng = new Random();
T[] elements = source.ToArray();
source.Clear();
// 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;
}
foreach (T element in elements)
{
source.Push(element);
}
}
如何让算法作用于传递的实际堆栈
在哪
由于Stack
是一种引用类型,您不需要在此处使用ref
参数,并且您不会尝试重新分配引用本身
默认情况下,引用是按值传递的,但该值(引用)指向堆上的同一对象,换句话说,您有两个引用指向同一对象,这很好-所有操作都将在原始堆栈
对象上执行
编辑:
根据您的评论,我建议您重新设计,不要修改原始的堆栈
,这一点从一开始就很麻烦:
public static IEnumerable<T> Shuffle<T>(Stack<T> source)
{
Random rng = new Random();
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;
}
}
使用Random
时也要小心-您可能希望将其传入。在这一点上,你可以使用而不是你自己的-这是更好的重用比重新发明
最终编辑:
看起来您只是想在适当的位置洗牌堆栈
——请改用扩展方法:
public static void Shuffle<T>(this Stack<T> source)
{
Random rng = new Random();
T[] elements = source.ToArray();
source.Clear();
// 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;
}
foreach (T element in elements)
{
source.Push(element);
}
}
堆栈不需要像那样通过引用传递,因为引用类型(如
stack
)已经通过引用传递了。在引用参数上使用ref
或out
修饰符的唯一原因是,如果您想实际修改引用本身(例如创建一个新的堆栈
,并将其作为一种可选的返回方法分配给参数——与C中的双指针相同).堆栈不需要像那样通过引用传递,因为引用类型(如堆栈
)已经通过引用传递。在引用参数上使用ref
或out
修饰符的唯一原因是,如果您想实际修改引用本身(例如创建一个新的堆栈
,并将其作为一种可选的返回方法分配给参数——与C中的双指针相同)。因为堆栈是一个类,我认为在这种情况下不需要ref关键字。如果没有它,它应该可以工作。因为Stack是一个类,我认为在这种情况下不需要ref关键字。
没有它应该可以用。使用Jon的:你不需要
ref
,但我几乎要说把它留在里面。返回一个IEnumerable
和修改传入集合的组合是相当可疑的。使用Jon's:您不需要ref
,但我几乎要说的是保留它。返回IEnumerable
和修改传入集合的组合非常可疑。那么为什么下面的代码以原始形式显示堆栈<代码>洗牌。洗牌(游戏组)foreach(gameDeck中的var项){System.Console.WriteLine(item.cardName);}
@FrankAMan:我想你误解了迭代器在C#中是如何阻止/产生的:结果是惰性地评估的——除非你迭代DoShuffle()的结果
或执行类似于Doshuffle.Shuffle(gameDeck).ToList()的操作。
您的迭代器块甚至无法启动,并且您的gameDeck尚未清除。感谢您的帮助。我根据乔恩·斯基特的帖子改编了我的版本。我只需要一些我可以调用Doshuffle.Shuffle(游戏组)的东西
和gameDeck(这是一个堆栈)被洗牌。我希望修改原始堆栈,而不是返回每个元素。似乎在你的方法中,我必须使用foreach循环来让牌组洗牌。还有其他的方法吗?@FrankAMan:Updated-使用扩展方法谢谢,了解更多细节。这很好地工作,而且对于我所有的不同