离开方法时从列表中丢失值
Losing values from list when leaving method
我在使用以下代码中的 2 个列表时遇到问题:
internal class Program
{
private static readonly List<char[]> permutations = new List<char[]>();
private static void Main()
{
string str = "0123456789";
char[] arr = str.ToCharArray();
GetPer(arr);
//2. here we have lost all the values
Console.ReadKey();
}
private static void Swap(ref char a, ref char b)
{
if (a == b) return;
a ^= b;
b ^= a;
a ^= b;
}
public static void GetPer(char[] list)
{
int x = list.Length - 1;
GetPer(list, 0, x);
}
private static void GetPer(char[] list, int k, int m)
{
if (k == m)
{
permutations.Add(list); //1. here we add value to the list
}
else
for (int i = k; i <= m; i++)
{
Swap(ref list[k], ref list[i]);
GetPer(list, k + 1, m);
Swap(ref list[k], ref list[i]);
}
}
}
有 2 条评论,第一个在 void GetPer
中,我们将值添加到列表中。第二条评论在 void Main
中,我们丢失了所有以前的值。如果需要任何解释,代码主要是从此处复制粘贴的 Listing all permutations of a string/integer。我怎样才能避免这个引用类型问题?
您一遍又一遍地添加对同一个列表的引用。您复制的方法交换两个值,递归 运行s 另一个排列,然后将它们交换回来。最终,在您 运行 完成所有排列后,列表又回到了它开始的位置。
原始程序只是将排列写入控制台,因此在每次排列后展开更改并不重要。如果在将列表添加到结果时复制列表,您应该会看到所有排列:
private static void GetPer(char[] list, int k, int m)
{
if (k == m)
{
permutations.Add((char[])(list.Clone())); //1. here we add a clone of the value to the list
}
else
for (int i = k; i <= m; i++)
{
Swap(ref list[k], ref list[i]);
GetPer(list, k + 1, m);
Swap(ref list[k], ref list[i]);
}
}
我会注意到我发现这不是阅读"your"代码,而是调试它。有策略地放置断点和监视可以使此类问题更容易解决。调试是理解代码中问题的宝贵技能,尤其是您未编写的代码。
你可以从this的回答中了解到,所有数组都是引用类型。
这意味着,当您在这行代码中将数组添加到数组列表时:
permutations.Add(list);
您实际上是在一遍又一遍地添加相同的数组。由于每次来回交换该数组中的值,您都会获得对同一数组的引用列表。
如果我没理解错的话,您想在您创建的第一个数组中列出所有可能的字符顺序。
为此,您需要克隆您的数组,而不是使用相同的引用。
底线:
您应该将添加到 collection 行更改为:
permutations.Add((char[])list.Clone());
这样,您添加的不是相同的引用,而是它的克隆,您的最终列表将充满不同的数组。
我在使用以下代码中的 2 个列表时遇到问题:
internal class Program
{
private static readonly List<char[]> permutations = new List<char[]>();
private static void Main()
{
string str = "0123456789";
char[] arr = str.ToCharArray();
GetPer(arr);
//2. here we have lost all the values
Console.ReadKey();
}
private static void Swap(ref char a, ref char b)
{
if (a == b) return;
a ^= b;
b ^= a;
a ^= b;
}
public static void GetPer(char[] list)
{
int x = list.Length - 1;
GetPer(list, 0, x);
}
private static void GetPer(char[] list, int k, int m)
{
if (k == m)
{
permutations.Add(list); //1. here we add value to the list
}
else
for (int i = k; i <= m; i++)
{
Swap(ref list[k], ref list[i]);
GetPer(list, k + 1, m);
Swap(ref list[k], ref list[i]);
}
}
}
有 2 条评论,第一个在 void GetPer
中,我们将值添加到列表中。第二条评论在 void Main
中,我们丢失了所有以前的值。如果需要任何解释,代码主要是从此处复制粘贴的 Listing all permutations of a string/integer。我怎样才能避免这个引用类型问题?
您一遍又一遍地添加对同一个列表的引用。您复制的方法交换两个值,递归 运行s 另一个排列,然后将它们交换回来。最终,在您 运行 完成所有排列后,列表又回到了它开始的位置。
原始程序只是将排列写入控制台,因此在每次排列后展开更改并不重要。如果在将列表添加到结果时复制列表,您应该会看到所有排列:
private static void GetPer(char[] list, int k, int m)
{
if (k == m)
{
permutations.Add((char[])(list.Clone())); //1. here we add a clone of the value to the list
}
else
for (int i = k; i <= m; i++)
{
Swap(ref list[k], ref list[i]);
GetPer(list, k + 1, m);
Swap(ref list[k], ref list[i]);
}
}
我会注意到我发现这不是阅读"your"代码,而是调试它。有策略地放置断点和监视可以使此类问题更容易解决。调试是理解代码中问题的宝贵技能,尤其是您未编写的代码。
你可以从this的回答中了解到,所有数组都是引用类型。
这意味着,当您在这行代码中将数组添加到数组列表时:
permutations.Add(list);
您实际上是在一遍又一遍地添加相同的数组。由于每次来回交换该数组中的值,您都会获得对同一数组的引用列表。
如果我没理解错的话,您想在您创建的第一个数组中列出所有可能的字符顺序。
为此,您需要克隆您的数组,而不是使用相同的引用。
底线:
您应该将添加到 collection 行更改为:
permutations.Add((char[])list.Clone());
这样,您添加的不是相同的引用,而是它的克隆,您的最终列表将充满不同的数组。