【问题标题】:Help with Linq and Dictionary's ContainsKey method帮助 Linq 和 Dictionary 的 ContainsKey 方法
【发布时间】:2010-08-18 03:10:51
【问题描述】:

我正在编写一个工具,该工具的第一部分是收集我们公共 API 中的所有头文件。问题是,两个头文件有重复的文件名(但它们位于不同的文件夹中)。这会在创建字典时出现问题。

最初我编写了一个 foreach 循环来将 FileInfo 实例收集到字典中。但是最近我正在学习 LINQ,我想将 foreach 循环转换为 LINQ 语句。 问题是当它执行时,它抱怨重复的文件名。

这是原始代码:

public Dictionary<String, FileDependency> GetSDKFiles(DirectoryInfo dir)
{
    Dictionary<String, FileDependency> list = new Dictionary<String, FileDependency>();
    foreach (FileInfo info in dir.EnumerateFiles("*.h", SearchOption.AllDirectories))
    {
        String key = info.Name.ToLower();
        if (list.ContainsKey(key) == false)
        {
            list.Add(key, new FileDependency(info.FullName));
        }
        else
        {
            Debug.Print("Duplicate key: {0}", info.Name);
            Debug.Print("  File: {0}", info.FullName);
            Debug.Print("  Have: {0}", list[key].FullFileName);
        }
    }

    return list;
}

我尝试像这样变成 LINQ:

public Dictionary<String, FileDependency> GetSDKFilesLINQ(DirectoryInfo dir)
{
    var files = from info in dir.EnumerateFiles("*.h", SearchOption.AllDirectories)
                let key = info.Name.ToLower()
                let dep = new FileDependency(info.FullName)
                select new { key, dep };
    return files.ToDictionary(v => v.key, v => v.dep);
}

但是在运行时我得到了这个:

已添加具有相同密钥的项目。

在 foreach 循环中很容易避免这种情况,因为我调用了 ContainsKey 方法来确保没有重复项。但是 LINQ 等价物是什么?

我在哪里使用? - 如何? 我使用群组吗? - 如何?

谢谢。

【问题讨论】:

标签: c# linq dictionary linq-to-objects


【解决方案1】:
var files = dir.EnumerateFiles("*.h", SearchOption.AllDirectories)
               .GroupBy(file => file.Name.ToLower())
               .Select(group => new {Key = group.Key, Value = group.First()})
               .ToDictionary(a => a.Key, a => new FileDependency (a.Value.FullName));

如果你有MoreLinq,你可以这样做:

var files =  dir.EnumerateFiles("*.h", SearchOption.AllDirectories)
                .DistinctBy(file => file.Name.ToLower())
                .ToDictionary(file => new FileDependency (a.Value.FullName));

或者,您可以为文件编写自己的IEqualityComparer 实现并使用标准的Distinct 方法。这里的整个问题是Distinct(至少从 .NET 3.5 开始)没有允许将您自己的“独特性”定义插入为 lambda 表达式的重载。

【讨论】:

    【解决方案2】:

    您可以按键分组并从组中取出第一个值作为dep:

    public Dictionary<String, FileDependency> GetSDKFilesLINQ(DirectoryInfo dir)
    {
        var files = from info in dir.EnumerateFiles(
                        "*.h", SearchOption.AllDirectories)
                    let key = info.Name.ToLower()
                    let dep = new FileDependency(info.FullName)
                    group dep by key into g
                    select new { key = g.Key, dep = g.First() };
        return files.ToDictionary(v => v.key, v => v.dep);
    }
    

    这将默默地忽略重复项。或者,您可以使用 Lookup 代替字典:

    public ILookup<String, FileDependency> GetSDKFilesLINQ2(DirectoryInfo dir)
    {
        var files = from info in dir.EnumerateFiles(
                        "*.h", SearchOption.AllDirectories)
                    let key = info.Name.ToLower()
                    let dep = new FileDependency(info.FullName)
                    select new { key, dep };
        return files.ToLookup(v => v.key, v => v.dep);
    }
    

    查找时的索引器将返回IEnumerable&lt;FileDependency&gt;,因此您可以看到所有值。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-07-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-08
      • 1970-01-01
      • 2015-06-30
      相关资源
      最近更新 更多