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>>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:
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!
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 });
精彩评论