将多个词典的值合并到一个列表中

时间:2016-08-29 07:39:49

标签: c# linq dictionary

我想将多个词典的值(准确地说是3个)合并到一个列表中。我当前的解决方案使用linq首先组合字典,然后将值转换为列表。

private List<Part> AllParts()
{
    return walls.Concat(floors)
                .Concat(columns)
                .ToDictionary(kvp => kvp.Key, kvp => kvp.Value)
                .Values
                .ToList();
}

首先合并列表似乎是多余的。我怎样才能改善这个?

3 个答案:

答案 0 :(得分:1)

您可以通过连接字典并选择值而不转换为字典来简化此代码:

E: Package 'php5-mcrypt' has no installation candidate
shwekayin@shwekayin-VirtualBox:/opt/lampp/htdocs$ composer create-project --prefer-dist laravel/laravel blog1
Installing laravel/laravel (v5.3.0)
  - Installing laravel/laravel (v5.3.0)
    Loading from cache

Created project in blog1
> php -r "file_exists('.env') || copy('.env.example', '.env');"
Loading composer repositories with package information
Updating dependencies (including require-dev)
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - laravel/framework v5.3.4 requires ext-mbstring * -> the requested PHP extension mbstring is missing from your system.
    - laravel/framework v5.3.3 requires ext-mbstring * -> the requested PHP extension mbstring is missing from your system.
    - laravel/framework v5.3.2 requires ext-mbstring * -> the requested PHP extension mbstring is missing from your system.
    - laravel/framework v5.3.1 requires ext-mbstring * -> the requested PHP extension mbstring is missing from your system.
    - laravel/framework v5.3.0 requires ext-mbstring * -> the requested PHP extension mbstring is missing from your system.
    - Installation request for laravel/framework 5.3.* -> satisfiable by laravel/framework[v5.3.0, v5.3.1, v5.3.2, v5.3.3, v5.3.4].

  To enable extensions, verify that they are enabled in those .ini files:
    - /etc/php/7.0/cli/php.ini
    - /etc/php/7.0/cli/conf.d/10-opcache.ini
    - /etc/php/7.0/cli/conf.d/10-pdo.ini
    - /etc/php/7.0/cli/conf.d/20-calendar.ini
    - /etc/php/7.0/cli/conf.d/20-ctype.ini
    - /etc/php/7.0/cli/conf.d/20-exif.ini
    - /etc/php/7.0/cli/conf.d/20-fileinfo.ini
    - /etc/php/7.0/cli/conf.d/20-ftp.ini
    - /etc/php/7.0/cli/conf.d/20-gettext.ini
    - /etc/php/7.0/cli/conf.d/20-iconv.ini
    - /etc/php/7.0/cli/conf.d/20-json.ini
    - /etc/php/7.0/cli/conf.d/20-phar.ini
    - /etc/php/7.0/cli/conf.d/20-posix.ini
    - /etc/php/7.0/cli/conf.d/20-readline.ini
    - /etc/php/7.0/cli/conf.d/20-shmop.ini
    - /etc/php/7.0/cli/conf.d/20-sockets.ini
    - /etc/php/7.0/cli/conf.d/20-sysvmsg.ini
    - /etc/php/7.0/cli/conf.d/20-sysvsem.ini
    - /etc/php/7.0/cli/conf.d/20-sysvshm.ini
    - /etc/php/7.0/cli/conf.d/20-tokenizer.ini
  You can also run `php --ini` inside terminal to see which files are used by PHP in CLI mode.

它看起来是最短且最易读的解决方案。您可以通过仅使用值来避免连接集合:

return walls.Concat(floors)
            .Concat(columns)
            .Select(kvp => kvp.Value)
            .ToList();

但是,我认为这里没有任何可读性,可维护性或性能改进。

P.S。我假设你的词典没有重复。此代码将包含重复值,而return walls.Values .Concat(floors.Values) .Concat(columns.Values) .ToList(); 方法将在密钥复制上引发异常。

答案 1 :(得分:1)

首先,一些有用的链接:

Combine multiple dictionaries into a single dictionary

Combine multiple dictionaries with same key in them into one dictionary with the sum of values

Merging dictionaries in C#

基本上,首先合并字典是必须的,但是有更多有效的方法可以避免重复,例如:

选项1

var dictionaries = new[] { walls, floors, columns };
var result = dictionaries
  .SelectMany(d => d)
  .GroupBy(
    kvp => kvp.Key,
    (key, kvps) => new { Key = key, Value = kvps.Sum(kvp => kvp.Value) }
  )
  .ToDictionary(x => x.Key, x => x.Value).ToList();
return result;

适用于任意数量的词典,而不仅仅是3。

选项2

var result = walls.Union(floors).Union(columns)
             .ToDictionary (k => k.Key, v => v.Value).ToList();
return result;

避免重复:

var result = walls.Concat(floors).Concat(columns).GroupBy(d => d.Key)
             .ToDictionary (d => d.Key, d => d.First().Value).ToList();

答案 2 :(得分:1)

Dictionary公开了一个名为Values的属性,它基本上是该词典中所有值的只读集合。这是在您不关心密钥时获得所有价值的最简单方法,而且这是组合它们的最简单方法:

var allParts = walls.Values
               .Concat(floors.Values)
               .Concat(columns.Values);

这比合并字典的各种方法更简单,也可能更高效,使用LINQ查询将KeyValuePairs转换为Parts等等 - 你不关心这里的Dictionariness,只关注值列表 - 所以把它当作一个价值清单。

但有一件事是,如果存在重复的Part,这将不会删除。您可以使用Union()代替Concat()来完成此操作。