【问题标题】:The problem with List Initialization with capacity using Enumerable.Repeat [duplicate]使用 Enumerable.Repeat 进行容量列表初始化的问题 [重复]
【发布时间】:2020-05-12 07:06:29
【问题描述】:

如果我们试图用容量和默认值初始化一个列表,就像我们在 C++ 中用大小和默认值初始化一个向量一样,比如我正在创建一个字典列表来构建一个带有权重的图,有通常有两种方法:

1) 使用for循环手动构建列表:

var graph= new List<Dictionary<int, int>>();
for (var i = 0; i < n; i++)
{
    graph.Add(new Dictionary<int, int>());
}

2) 使用 Enumberable.Repeat() 初始化列表:

var graph= Enumerable.Repeat(new Dictionary<int, int>(), n).ToList();

假设现在我们有一个带有权重的节点对(边)列表,并且想要在此之上构建一个图,我们会这样写:

foreach (var list in lists) // List = [[0, 1, 100],[1,2,100],[0,2,500]]
{
    int a = list[0], b = list[1], weight= list[2];
    if (!graph[a].ContainsKey(b))
        graph[a].Add(b, weight);
}

虽然这两种方法理论上都应该有效,但结果却大不相同。 当我尝试使用以下代码打印图表时:

for (var i = 0; i < graph.Count; i++)
{
    var node = graph[i];
    foreach (var pair in node)
    {
        Console.WriteLine($"{i} -> {pair.Key} with price {pair.Value}");
    }
}

1) 的结果如下所示:

// Correct output
0 -> 1 with price 100
0 -> 2 with price 500
1 -> 2 with price 100

但是 2) 的结果看起来像:

// Incorrect result
0 -> 1 with price 100
0 -> 2 with price 100
1 -> 1 with price 100
1 -> 2 with price 100
2 -> 1 with price 100
2 -> 2 with price 100

在这种情况下,Repeat 方法的行为似乎很奇怪,在 Doc 上,没有提到这种行为。

我对这种行为的看法是重复方法在内存中创建 ONLY ONE 值并将所有列表条目指向相同的内存位置。在这种情况下,内存中只创建一个字典,而不是为每个列表条目创建一个新字典。字典上的所有操作实际上都发生在同一个位置。但这并不能解释第二个结果中的奇怪输出。

有什么想法吗?这是 Enumerable.Repeat() 方法中的错误还是我做错了?用默认值初始化列表的更好方法是什么?

【问题讨论】:

  • 我认为不会。
  • Dictionary&lt;int, int&gt; 是引用类型,您重复该值,该值存储在内存中的同一位置。 sources 表明,RepeatIterator 在循环中返回相同的值,无需复制
  • @Aven 你正在修改同一个实例
  • var graph = Enumerable.Range(0,n).Select(i =&gt; new Dictionary&lt;int, int&gt;()).ToList(); 我更喜欢循环。
  • @Aven 此方法不会创建值的新副本,它只是重复该值。在引用类型的情况下,每个值都指向内存中的相同位置。因此你会得到一个不正确的输出,因为修改同一个实例并且不能使用第二种方式将[0,2,500]添加到字典中(在这种情况下,值2的键已经存在)

标签: c# enumerable


【解决方案1】:

Enumerable.Repeat 只是重复传递的值n 次。您创建一个字典,将其传递给Repeat,它会生成一个n 对该字典的引用列表。

如果您想基于函数生成序列,则可以使用 MoreLinq Generate 扩展名。

【讨论】:

  • 或类似Enumerable.Range(0, n).Select(_ =&gt; new Dictionary&lt;...&gt;())
猜你喜欢
  • 2023-04-03
  • 1970-01-01
  • 1970-01-01
  • 2013-12-21
  • 1970-01-01
  • 1970-01-01
  • 2012-08-04
  • 2021-04-07
  • 2011-10-11
相关资源
最近更新 更多