将具有重复值的集合拆分为范围,C#

时间:2015-04-06 09:23:03

标签: c# linq collections generic-collections

我有两个清单:

List<string> keys = new List<string>() 
{ 
    "REPORTMONTH", 
    "CONTRACT", "DATE", "AMOUNT",
    "CONTRACT", "DATE", "AMOUNT"
};

List<string> values = new List<string>() 
{   
    "01", 
    "ABC123", "01022014", "300.00", 
    "DEF345", "03042014", "400.00"
};

第一个列表表示可以具有某些重复的关键字。第二个列表包含与第一个列表中的键相关联的值(按索引)。结果输出应为List<Dictionary<string, string>>类型,并包含:

1st dictionary

key                   value
"REPORTMONTH"        "01"
"CONTRACT"           "ABC123"
"DATE"               "01022014"
"AMOUNT"             "300.00"

2nd dictionary

key                  value
"REPORTMONTH"        "01"
"CONTRACT"           "DEF345"
"DATE"               "03042014"
"AMOUNT"             "400.00"

即。不重复的键应该出现在两个词典中,其余的键应该分成带有相关值的词典。 注意,根本不可能有重复,或者超过2。

抱歉,我无法展示我对此问题的尝试,因为我不确定如何开始。也许使用LINQ和分组可以解决问题?

谢谢。

2 个答案:

答案 0 :(得分:2)

您可以首先使用Enumerable.Zip()获取一系列键/值对并将列表转换为lookup,然后将该列表处理为两个词典:

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main()
        {
            List<string> keys = new List<string>
            {
                "REPORTMONTH",
                "CONTRACT", "DATE", "AMOUNT",
                "CONTRACT", "DATE", "AMOUNT"
            };

            List<string> values = new List<string>
            {
                "01",
                "ABC123", "01022014", "300.00",
                "DEF345", "03042014", "400.00"
            };

            var combined = Enumerable.Zip(
                keys, values, (key, value) => new { Key = key, Value = value})
                .ToLookup(entry => entry.Key);

            var dicts = new []
            {
                new Dictionary<string, string>(),
                new Dictionary<string, string>()
            };

            foreach (var items in combined)
            {
                int count = 0;
                string lastKey = null;

                foreach (var item in items.Take(2))
                {
                    dicts[count++][item.Key] = item.Value;
                    lastKey = item.Key;
                }

                if (count == 1)
                    dicts[1][lastKey] = dicts[0][lastKey];
            }

            dump("1st dictionary", dicts[0]);
            dump("2nd dictionary", dicts[1]);
        }

        static void dump(string title, Dictionary<string, string> data)
        {
            Console.WriteLine(title);

            foreach (var item in data)
                Console.WriteLine("Key: {0}, Value: {1}", item.Key, item.Value);

            Console.WriteLine();
        }
    }
}

答案 1 :(得分:2)

你可以用一种看起来不那么优雅,需要一些循环的方式来做到这一点。请注意,如果有超过2个词典,这也可以使用。

public static void Main(params string[] args)
{
    List<string> keys = new List<string>()  { 
        "REPORTMONTH", 
        "CONTRACT", "DATE", "AMOUNT",
        "CONTRACT", "DATE", "AMOUNT"
    };

    List<string> values = new List<string>() {   
        "01", 
        "ABC123", "01022014", "300.00", 
        "DEF345", "03042014", "400.00"
    }; 

    var pairs = keys.Select((key, ndx) => new { Key = key, Value = values[ndx] });
    var groups = pairs.GroupBy(e => e.Key)
        .ToDictionary(g => g.Key, g => g.Select(kvp => kvp.Value).ToArray());
    var dictionaries = new Dictionary<string, string>[groups.Max(g => g.Value.Length)];

    for (var i = 0; i < dictionaries.Length; i++)
    {
        dictionaries[i] = new Dictionary<string,string>();
        foreach (var g in groups) 
        {
            if (g.Value.Length == 1)
                dictionaries[i][g.Key] = g.Value[0];
            else if (g.Value.Length > i)
                dictionaries[i][g.Key] = g.Value[i];
        }
    }

    // print content
    for (var i = 0; i < dictionaries.Length; i++)
    {
        Console.WriteLine("Dictionary {0}:", i + 1);
        Console.WriteLine(string.Join(Environment.NewLine, dictionaries[i].Select(e => string.Format("{0} = {1}", e.Key, e.Value))));
        Console.WriteLine();
    }
    Console.ReadLine();
}