转换列表<对象>匿名类型到 Dictionary>

发布于 2024-10-28 02:07:57 字数 1347 浏览 1 评论 0 原文

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

数据是列表,如下所示。

{ 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> ,其中字典的键是 Security,值是包含所有日期/的 SortedList安全性的 z 分数值。

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

注意:此查询最初以不必要的复杂且措辞不当的方式发布。这可能就是为什么没有人回答的原因!我添加了链接,以防您想了解为什么输出采用这种形式。
C# LINQ Z-Score 查询输出到字典< ;string, SortedList>

I have a function that creates a local List<object> where the object is an anonymous type. I need to return these results in Dictionary<string, SortedList<DateTime, double>>.

The data is the the list looks like this.

{ 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 }

I would like to use LINQ to place these results into a Dictionary<string, SortedList<DateTime, double>> where the dictionary's key is the Security, and the value is a SortedList containing all the date/z-score values for the security.

I can do this in LINQ when it is a custom object, but how do you do it with an anonymous type object?

Note: This query was originally posted in an unnecessarily complicated, and poorly phrased way. Which is probably why no one answered it! I'm including the link in case you wanted to see why the output is in this form.
C# LINQ Z-Score query output to a Dictionary<string, SortedList<DateTime, double>>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

旧夏天 2024-11-04 02:07:57

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

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

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

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

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

如果您想探索他的解决方案,请查看他的 关于该主题的博客文章

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

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

So basically you're asking how to unbox an anonymous type from object?

First of all, I recommend not using a List<object> and just ... creating a custom class.

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

However, if for whatever reason you need to do this, try this approach from Jon Skeet:

I've always known that it's perfectly easy to return an instance of an anonymous type by declaring that the method will return object. However, it hadn't occurred to me before today that you can actually cast back to that type afterwards. Of course, you can't just use a normal cast expression - that requires the name of the type to be known at compile-time. But you can do a cast in a generic method... and you can use type inference to supply a type argument... and two anonymous type instance creation expressions will use the same type within the same assembly if the order, names and types of the properties are the same.

If you want to explore his solution, check out his blog post on the subject.

For completeness, I will post his code here:

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);            
    }
}

I must admit that, while I don't really like the idea of boxing/unboxing an anonymous type, his approach is pretty awesome, and takes up relatively few lines of code.

So, now that I've given you a possible solution, I must ask -- why are you doing it this way, as opposed to creating a simple class?

Edit: Also for completeness, here's how I would implement your particular problem using Jon Skeet's solution:

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;
}

In LINQPad, the above code results in the following data:

linqified data

素罗衫 2024-11-04 02:07:57

Pandincus 在 他的答案中给出了一种可能的解决方案。如果您使用 .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。看起来您已经在 您对原始问题的回答!

Pandincus gave one possible solution in his answer. Another solution with a smaller footprint is available to you if you're using .NET 4.0 and can take advantage of the 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);
}

This still feels hackish and ideally, since you're generating the result, you should avoid this mess by rethinking your approach and avoid adding the items to a List<object>. It looks like you have done just that in your answer to your original question!

勿忘初心 2024-11-04 02:07:57

这个没有经过测试。

 Dictionary<string, SortedList<DateTime, double>> dict = yourList.ToDictionary(kv => kv.Security , kv => new KeyValuePair(kv.Date, kv.zScore));

根据下面的评论编辑,您可以尝试List< SomeType > 而不是 List<对象>

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 });

This is not tested.

 Dictionary<string, SortedList<DateTime, double>> dict = yourList.ToDictionary(kv => kv.Security , kv => new KeyValuePair(kv.Date, kv.zScore));

Edit based on comments below, you could try List< SomeType > instead of 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 });
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文