【问题标题】:Creating Key/Value collections using LINQ To Objects使用 LINQ To 对象创建键/值集合
【发布时间】:2009-09-10 13:53:10
【问题描述】:

我正在尝试使用 LINQ To Objects 创建一个查询,该查询将为我提供文件,这些文件由文件名索引,其二进制数据的值映射为 byte[]

但是我找不到一种“简洁”的方法来做到这一点。我希望得到类似Dictionary<T,K> 的输出。

这是我目前所拥有的。示例 delimFileNames="1.jpg|2.jpg"

//Extract filenames from filename string
//and read file binary from file
//select result into a filename indexed collection
var result = from f in delimFileNames.Split(Constants.DDS_FILENAME_SEPARATOR)
            let filePath = Path.Combine(ddsClient.WorkingDirectory, f)
            let fileData = File.ReadAllBytes(filePath)
            select new KeyValuePair<string, byte[]>(f, fileData);

return result.ToDictionary(kvp => kvp.Key, kvp=> kvp.Value);

主要问题是为什么我不能使用无参数的 ToDictionary() 或直接转换。任何改进上述内容的建议或替代方案都表示赞赏。

【问题讨论】:

    标签: linq collections linq-to-objects


    【解决方案1】:

    ToDictionary() 必须为 KeyValuePair 提供一个特殊情况 - 当然,您可以将其添加为自己的扩展方法:

    public static Dictionary<TKey, TValue> ToDictionary<TKey, TValue>(
         IEnumerable<KeyValuePair<TKey, TValue>> source)
    {
        return source.ToDictionary(kvp => kvp.Key, kvp=> kvp.Value);
    }
    

    如果没有那个扩展方法,你可以这样做:

    var result = from f in delimFileNames.Split(Constants.DDS_FILENAME_SEPARATOR)
                                         .ToDictionary(f => f,
              // Outdented to avoid scrolling
              f => File.ReadAllBytes(Path.Combine(ddsClient.WorkingDirectory, f));
    

    基本上,查询表达式允许您执行所有时髦的“让”操作,但会强制您在末尾添加 select,这会使您将两个不同的值(键和字节数组)传播为两个属性。

    【讨论】:

    • +1 我想你潜伏在等待这些问题乔恩:P
    【解决方案2】:

    “主要的头疼是为什么我不能使用无参数的 ToDictionary() [...]”

    因为ToDictionary方法需要知道什么是key,什么是value。微软本可以为这种特殊情况创造一个重载,但没有,因为我想好处不是很大。但是没有什么能阻止您创建自己的扩展方法来实现这一点。

    “[...] 或直接演员。”

    因为您的 Linq 查询返回一个 IEnumerable&lt;KeyValuePair&lt;TKey, TValue&gt;&gt; 而不是 Dictionary&lt;TKey, TValue&gt;。它允许您枚举键/值对,但不允许通过键快速查找。

    请注意,Dictionary&lt;TKey, TValue&gt; 虽然是 IEnumerable&lt;KeyValuePair&lt;TKey, TValue&gt;&gt;(它实现了该接口),这意味着您可以像使用 Linq 查询一样遍历键/值对,但基础类型是 Dictionary , 这样您就可以通过按键快速查找。

    【讨论】:

      【解决方案3】:

      您不需要使用KeyValuePair&lt;,&gt;,而是可以使用匿名类型,它允许您使用比KeyValue 更具描述性的名称:

      var files =
          from fileName in delimFileNames.Split(Constants.DDS_FILENAME_SEPARATOR)
          let filePath = Path.Combine(ddsClient.WorkingDirectory, fileName)
          select new
          {
              Path = filePath,
              Data = File.ReadAllBytes(filePath)
          };
      
      return files.ToDictionary(file => file.Path, file => file.Data);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-12-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-06-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多