复制IEnumerable,List和Cast

时间:2011-10-18 13:22:11

标签: c# casting ienumerable

阅读此very interesting thread on duplicate removal后,我结束了这个=>

    public static IEnumerable<T> deDuplicateCollection<T>(IEnumerable<T> input)
    {
        var hs = new HashSet<T>();
        foreach (T t in input)
            if (hs.Add(t))
                yield return t;
    }        
顺便说一句,因为我是C#的新手并且来自Python,我在演员和这种事情之间有点迷失......我能够编译和构建:

            foreach (KeyValuePair<long, List<string>> kvp in d)
            {
                d[kvp.Key] = (List<string>) deDuplicateCollection(kvp.Value);
            }

但我必须在这里错过了一些东西...因为我得到了一个“System.InvalidCastException”@运行时,也许你能指出有关铸造的有趣事情以及我错在哪里?提前谢谢。

2 个答案:

答案 0 :(得分:3)

首先,关于该方法的用法。

删除演员表,在方法的结果上调用ToList()。该方法的结果是IEnumerable<string>,这不是List<string>。源最初 List<string>的事实无关紧要,您不会返回列表,而是yield return一个序列。

d[kvp.Key] = deDuplicateCollection(kvp.Value).ToList();

其次,您的deDuplicateCollection方法是多余的,Distinct()已经存在于库中并执行相同的功能。

d[kvp.Key] = kvp.Value.Distinct().ToList();

请确保指令中有using System.Linq;,以便您可以使用这些Distinct()ToList()扩展方法。

最后,您会注意到单独进行此更改 ,在尝试更改循环中的字典时会遇到新的异常。您无法在foreach中更新集合。做你想做的最简单的方法是完全省略显式循环。考虑

d = d.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.Distinct().ToList());

这使用了另一种Linq扩展方法ToDictionary()。注意:这会在内存中创建一个新字典并更新d以引用它。如果您需要保留d引用的原始字典,那么您需要以另一种方式处理。这里一个简单的选择是构建一个字典以隐藏d,然后用它来更新d

var shadow = new Dictionary<string, string>();
foreach (var kvp in d)
{ 
    shadow[kvp.Key] = kvp.Value.Distinct().ToList();
}

foreach (var kvp in shadow)
{
    d[kvp.Key] = kvp.Value;
}

这两个循环是安全的,但是你看到你需要循环两次以避免在枚举时更新原始集合的问题,同时还保留了内存中的原始集合。

答案 1 :(得分:2)

d[kvp.Key] = kvp.Value.Distinct().ToList();

已经有一个Distinct扩展方法可以删除重复项!