Преобразовать список <object>анонимного типа в словарь> - PullRequest
3 голосов
/ 30 марта 2011

У меня есть функция, которая создает локальный 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>>, где ключом словаря является Security, азначение представляет собой SortedList, содержащий все значения даты / z-счета для безопасности.

Я могу сделать это в LINQ, когда это пользовательский объект, но как вы делаете это с объектом анонимного типа?

Примечание. Первоначально этот запрос был опубликован излишне сложным и плохо сформулированным способом.Наверное, поэтому никто не ответил на это!Я включил ссылку на тот случай, если вы хотите узнать, почему вывод находится в этой форме.
C # LINQ Вывод запроса Z-Score в словарь>

Ответы [ 3 ]

7 голосов
/ 30 марта 2011

Итак, в основном вы спрашиваете, как распаковать анонимный тип из object?

Прежде всего, я рекомендую не использовать List<object> и просто ... создавать собственный класс.

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

Однако, если по какой-либо причине вам нужно сделать это, попробуйте этот подход от Джона Скита:

Я всегда знал, что очень просто вернуть экземпляр анонимного типа, заявив, что метод вернет объект. Однако до сегодняшнего дня мне не приходило в голову, что вы на самом деле можете вернуться к этому типу позже. Конечно, вы не можете просто использовать обычное выражение приведения - это требует, чтобы имя типа было известно во время компиляции. Но вы можете выполнить приведение в обобщенном методе ... и вы можете использовать вывод типа для предоставления аргумента типа ... и два выражения создания экземпляра анонимного типа будут использовать один и тот же тип в одной сборке, если порядок, имена и типы свойств одинаковы.

Если вы хотите изучить его решение, ознакомьтесь с его сообщением в блоге на эту тему.

Для полноты я выложу его код здесь:

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

Я должен признать, что, хотя мне не очень нравится идея упаковки / распаковки анонимного типа, его подход довольно удивителен и занимает относительно мало строк кода.

Итак, теперь, когда я дал вам возможное решение, я должен спросить - почему вы делаете это таким образом, в отличие от создания простого класса?

Редактировать: Также, для полноты, вот как я могу реализовать вашу конкретную проблему, используя решение Джона Скита:

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

4 голосов
/ 30 марта 2011

Пандинк дал одно возможное решение в своем ответе .Если вы используете .NET 4.0, вам доступно еще одно решение с меньшей занимаемой площадью, которое может использовать dynamic тип :

// 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>.Похоже, вы сделали именно это в своем ответе на свой первоначальный вопрос!

2 голосов
/ 30 марта 2011

Это не проверено.

 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 });
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...