将匿名类型的List <object>转换为Dictionary <string,sortedlist <datetime,=“”double =“”>&gt; </string,> </object>

时间:2011-03-30 01:16:21

标签: c# linq dictionary

我有一个创建本地List<object>的函数,其中对象是匿名类型。我需要在Dictionary<string, SortedList<DateTime, double>>中返回这些结果。

数据列表如下所示。

{ Security = "6752 JT", Date = {1/17/2011 12:00:00 AM}, zScore = 1 }
{ Security = "6753 JT", Date = {1/17/2011 12:00:00 AM}, zScore = 2 }
{ Security = "6754 JT", Date = {1/17/2011 12:00:00 AM}, zScore = 3 }
{ Security = "6752 JT", Date = {1/18/2011 12:00:00 AM}, zScore = 1 }
{ Security = "6753 JT", Date = {1/18/2011 12:00:00 AM}, zScore = 2 }
{ Security = "6754 JT", Date = {1/18/2011 12:00:00 AM}, zScore = 3 }
{ Security = "6752 JT", Date = {1/19/2011 12:00:00 AM}, zScore = 1 }
{ Security = "6753 JT", Date = {1/19/2011 12:00:00 AM}, zScore = 2 }
{ Security = "6754 JT", Date = {1/19/2011 12:00:00 AM}, zScore = 3 }

我想使用LINQ将这些结果放入Dictionary<string, SortedList<DateTime, double>>,其中字典的键是安全性,值是包含安全性的所有日期/ z分数值的SortedList。

当LINQ是自定义对象时,我可以在LINQ中执行此操作,但是如何使用匿名类型对象执行此操作?

注意:此查询最初是以不必要的复杂且措辞不当的方式发布的。这可能是没有人回答的原因!我想要包含链接,以防你想知道为什么输出是这种形式。
C# LINQ Z-Score query output to a Dictionary<string, SortedList<DateTime, double>>

3 个答案:

答案 0 :(得分:7)

所以基本上你问的是如何从object取消包装匿名类型?

首先,我建议不要使用List<object>而只是...创建自定义类。

public class SecurityScore {
    public string Security { get; set; }
    public DateTime Date { get; set; }
    public int ZScore { get; set; }
}

但是,如果出于任何原因需要这样做,请尝试Jon Skeet的这种方法:

  

我一直都知道通过声明该方法将返回对象来返回匿名类型的实例非常容易。但是,在我今天之前没有想到你之后可以实际回到那种类型。当然,您不能只使用普通的强制转换表达式 - 这需要在编译时知道类型的名称。但是你可以在泛型方法中进行强制转换......并且你可以使用类型推断来提供类型参数......如果顺序,名称和类型,两个匿名类型实例创建表达式将在同一个程序集中使用相同的类型属性是一样的。

如果您想探索他的解决方案,请查看他关于该主题的blog post

为了完整起见,我将在此处发布他的代码:

static class GrottyHacks
{
    internal static T Cast<T>(object target, T example)
    {
        return (T) target;
    }
}

class CheesecakeFactory
{
    static object CreateCheesecake()
    {
        return new { Fruit="Strawberry", Topping="Chocolate" };
    }

    static void Main()
    {
        object weaklyTyped = CreateCheesecake();
        var stronglyTyped = GrottyHacks.Cast(weaklyTyped,
            new { Fruit="", Topping="" });

        Console.WriteLine("Cheesecake: {0} ({1})",
            stronglyTyped.Fruit, stronglyTyped.Topping);            
    }
}

我必须承认,虽然我不喜欢装箱/取消装箱匿名类型的想法,但他的方法非常棒,并占用相对较少的代码。

所以,既然我已经给你一个可能的解决方案了,我必须问 - 为什么你这样做呢,而不是创建一个简单的类?

编辑:为了完整起见,以下是使用Jon Skeet解决方案实现特定问题的方法:

void Main()
{
    // Create a list of (boxed) anonymous objects
    var securitiesBoxed = new List<object>() {
        new { Security = "6752 JT", Date = DateTime.Parse("1/17/2011 12:00:00 AM"), zScore = 1 },
        new { Security = "6753 JT", Date = DateTime.Parse("1/17/2011 12:00:00 AM"), zScore = 2 },
        new { Security = "6754 JT", Date = DateTime.Parse("1/17/2011 12:00:00 AM"), zScore = 3 },
        new { Security = "6752 JT", Date = DateTime.Parse("1/18/2011 12:00:00 AM"), zScore = 1 },
        new { Security = "6753 JT", Date = DateTime.Parse("1/18/2011 12:00:00 AM"), zScore = 2 },
        new { Security = "6754 JT", Date = DateTime.Parse("1/18/2011 12:00:00 AM"), zScore = 3 },
        new { Security = "6752 JT", Date = DateTime.Parse("1/19/2011 12:00:00 AM"), zScore = 1 },
        new { Security = "6753 JT", Date = DateTime.Parse("1/19/2011 12:00:00 AM"), zScore = 2 },
        new { Security = "6754 JT", Date = DateTime.Parse("1/19/2011 12:00:00 AM"), zScore = 3 }
    };

    // Now, to convert to a Dictionary<string, SortedList<DateTime, double>>...
    var securitiesUnboxed = securitiesBoxed.Select(x => Cast(x, new { Security = "", Date = new DateTime(), zScore = 0 }))
        .GroupBy(x => x.Security)
        .ToDictionary(x => x.Key, x => x.OrderBy(y => y.Date));
}

// This is the static method that will cast our anonymous type
internal static T Cast<T>(object target, T example)
{
    return (T) target;
}

LINQPad中,上述代码会生成以下数据:

linqified data

答案 1 :(得分:4)

Pandincus在his answer中提供了一个可能的解决方案。如果您使用的是.NET 4.0,并且可以利用dynamic type

,则可以使用占用空间较小的另一种解决方案
// list is a List<object>
var query = list.Cast<dynamic>()
                .GroupBy(o => o.Security)
                .ToDictionary(o => o.Key,
                    o => new SortedList<DateTime, double>(o.ToDictionary(x => (DateTime)x.Date, x => (double)x.zScore)));

foreach (var item in query)
{
    Console.WriteLine("Security: " + item.Key);
    foreach (var kvp in item.Value)
        Console.WriteLine("Date: {0}, zScore: {1}", kvp.Key, kvp.Value);
}

这仍然感觉很乱,理想情况下,因为你产生的结果,你应该通过重新思考你的方法避免这种混乱,并避免将项目添加到List<object>。您似乎已经在your answer to your original question!

中完成了这项工作

答案 2 :(得分:2)

未经测试。

 Dictionary<string, SortedList<DateTime, double>> dict = yourList.ToDictionary(kv => kv.Security , kv => new KeyValuePair(kv.Date, kv.zScore));
根据以下评论

修改,您可以尝试List< SomeType >代替List< object >

class SomeType
{
    public string Security {get;set;}
    public DateTime Date {get;set;}
    public int zScore {get;set;}
}

var results = new List<SomeType>(); 
results.Add(new { Security = secRank.Symbol, Date = sec.First().Date, zScore = zScore });