如何合并/压缩不同类型的通用列表(并将结果转换为字典)?

时间:2011-08-18 13:16:09

标签: c# linq generics merge

我需要从一些Excel工作表中读取数据。 excel表中的数据已经过格式化,我可以通过这种方法获得所需的数据。

这就是我在做的事情:

using (var conn = new OleDbConnection(strBld.ToString()))
{
    conn.Open();

    IEnumerable<IDictionary<string, object>> excelDataRaw = 
        conn.Query("select * from [Curves$A:IT]").
        Cast<IDictionary<string, object>>();

    int i = 0;
    string previousKey = null;
    var curve = new List<IEnumerable<object>>();
    var excelData = new Dictionary<string, IDictionary<object, object>>();
    //var excelData = new Dictionary<string, IDictionary<string, decimal>>();

    foreach (var key in excelDataRaw.Select(dictionary => dictionary.Keys).
        ElementAt(i))
    {
        string key1 = key;
        // gets the data from one column within the excel file
        curve.Add(excelDataRaw.Select(col => col[key1]).
            Where(row => row != null).ToList());

        if (i % 2 == 0)
        {
            // store the column header
            previousKey = key;
        }

        if (i % 2 == 1)
        {
            // merge the data from the first column (keys)
            // with the data from the second column (values)
            IEnumerable<object> keys = curve[i - 1];
            IEnumerable<object> values = curve[i];
            // cast works but than you can't zip the lists together
            //IEnumerable<string> keys = curve[i - 1].Cast<string>();
            //IEnumerable<decimal> values = curve[i].Cast<decimal>();

            // zip them together on their index
            var dic = keys.Zip(values, (k, v) => new { k, v }).
                ToDictionary(x => x.k, x => x.v);

            if (previousKey != null)
            {
                if (!excelData.ContainsKey(previousKey))
                {
                    excelData.Add(previousKey, dic);
                }
            }
        }

        ++i;
    }
}

我从excel文件中提取所有数据(excelDataRaw)。然后我选择所有属于一个列表(曲线)的数据,并将两个彼此属于一个列表组合成一个字典(dic)。最终结果是一个字典(excelData),它包含excel文件中的列头作为键(previousKey),以及与此列相关的数据作为字典(dic)。

我想从

转换字典(excelData)
Dictionary<string, IDictionary<object, object>> 

进入

Dictionary<string, IDictionary<string, decimal>> 

但我无法将对象转换为字符串或小数,并且在将每个列表转换为所需类型后,我无法将列表压缩在一起以获取字典(dic)。有谁知道如何达到预期的结果(类型)?

2 个答案:

答案 0 :(得分:1)

ExcelDataRaw属于Dictionary<string, IDictionary<object, object>>类型,因此需要IDictionary<object, object>作为值。您无法将Dictionary<string,decimal>转换为IDictionary<object,object>,因为IDictionary不是协变接口 - 请参阅http://msdn.microsoft.com/en-us/library/dd469487.aspx

解决方案是将ExcelDataRaw的类型更改为Dictionary<string, IDictionary<string, decimal>>或保持原样,并且在尝试使用该字典中的值时,将这些值转换为正确的类型:

foreach(var kv in ExcelDataRaw)
{
   Dictionary<string,decimal> convertedValue=kv.Value.ToDictionary(x=>(string)x.Key,x=>(decimal)x.Value);
   // or convert it even further down the road
   string lookup = "abc";
   decimal v = (decimal)kv.Value[lookup];
}

答案 1 :(得分:0)

我找到了一个解决方案,我一定忽略了昨天的明显。一个良好的睡眠之夜有时会有所帮助:)。

IEnumerable<object> keys = curve[i - 1];
IEnumerable<object> values =
    curve[i].Where(content => decimal.TryParse(content.ToString(), out num));
    Dictionary<string, decimal> dic =
        keys.Zip(values, (k, v) => new { k, v }).ToDictionary(
            x => (string)x.k, x => decimal.Parse(x.v.ToString()));
if (previousKey != null)
{
    if (!excelData.ContainsKey(previousKey))
    {
        excelData.Add(previousKey, dic);
    }
}