C # HashSet объединение в IEnumerable в выражении LINQ Func не работает (возможна ошибка прекомпилятора) - PullRequest
1 голос
/ 14 октября 2010

Я использую Microsoft .NET Framework 4.0.

Я столкнулся с этим, используя Aggregate на Dictionary<T, List<T>>, чтобы извлечь набор значений типа T, используемых во всех списках типа List<T> в словаре. Вот самый простой случай, который я мог придумать, который демонстрирует такое же поведение.

Во-первых, как указано в документации , следующее работает :

var set = new HashSet<int>();
var list = new LinkedList<int>();
var newSet = set.Union(list);

То есть я могу вызвать Union для HashSet с List в качестве аргумента (поскольку он реализует IEnumerable).

Принимая во внимание, что эквивалентное выражение в аргументе Func выражения LINQ Aggregate выдает ошибку (по крайней мере, прекомпилятор):

new List<int>[] { new List<int>() }.Aggregate(new HashSet<int>(), (acc, list) => acc.Union(list));

Он ожидает, что аргумент Union будет HashSet, и будет взаимодействовать, если он ему дан, вопреки его поведению вне выражений LINQ / Func.

Примером из реальной жизни, который я использовал, когда столкнулся с проблемой, было:

public AdjacencyListGraph(Dictionary<TVertex, LinkedList<TVertex>> adjacencyList)
{
    var vertices = adjacencyList.Aggregate(new HashSet<TVertex>(),
    (vertices, list) => vertices.Union(list.Value));
}

Который жалуется, что не может конвертировать IEnumerable<TVertex> в HashSet<TVertex> ...

Ответы [ 3 ]

2 голосов
/ 14 октября 2010

Проблема здесь в том, что вы понимаете метод Select. Переданная лямбда не получает список, а вместо этого элементы списка. Таким образом, переменная, которую вы назвали list, на самом деле имеет тип int, который не совместим с Union.

Вот более наглядный пример того, что вы пытаетесь сделать

new List<int>().Select( (int list) => new HashSet<int>().Union(list));

С удалением умозаключения типа гораздо понятнее, почему это не работает.

0 голосов
/ 14 октября 2010

Проблема на самом деле заключается в попытке заменить тип аккумулятора HashSet на метод IEnumerable, .Union не добавляет элементы в HashSet, но возвращает новый IEnumerable в результирующем объединении.Ваш код для следующего:

    // select from keys
    var vertices = new HashSet<TVertex>(adjacencyList.Keys);

или

    // select from values
    var vertices = new HashSet<TVertex>(adjacencyList.SelectMany(dictEntry => dictEntry.Value));
0 голосов
/ 14 октября 2010
new List<int>().Select(list => new HashSet<int>().Union(list));

Я думаю, вы ожидаете использовать здесь SelectMany, если только вы не хотите, чтобы результат был IEnumerable<IEnumerable<T>>.

...