Если мы пытаемся инициализировать список с емкостью и значением по умолчанию, точно так же, как мы инициализируем вектор в 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, о таком поведении не упоминается.
Я полагаю, что это поведение заключается в том, что метод Repeat создает значение ONLY ONE в памяти и указывает все записи списка на одно и то же место в памяти. В этом случае в памяти создается только один словарь вместо нового словаря, создаваемого для каждого элемента списка. И все операции со словарем на самом деле происходят в одном и том же месте. Но это не объясняет странный вывод во втором результате.
Любая мысль? Это ошибка в этом методе Enumerable.Repeat() или я делаю это неправильно? Каков наилучший способ инициализировать список значением по умолчанию?
Dictionary<int, int>
— это ссылочный тип, вы повторяете значение, хранящееся в том же месте в памяти. источники показывают, чтоRepeatIterator
возвращает то же значение в цикле, без копирования - person Pavel Anikhouski   schedule 26.01.2020var graph = Enumerable.Range(0,n).Select(i => new Dictionary<int, int>()).ToList();
Я бы предпочел петлю. - person Jimi   schedule 26.01.2020[0,2,500]
в словарь вторым способом (ключ со значением2
в этом случае уже существует) - person Pavel Anikhouski   schedule 26.01.2020