将列表项重组为组

时间:2016-12-03 19:25:40

标签: c# algorithm linq data-structures

我有一个List,其中包含以下内容:

{ 
 Answer: "test answer",
 FaqTopicName :"General",
 Question: "test question",
 SortOrder: 0
},

{ 
 Answer: "...",
 FaqTopicName :"General",
 Question: "...",
 SortOrder: 1
},

... (repeated)

我希望重新构建List,以便它现在包含在对象内部分组的每个列表项。结果对象将如下所示,并将包含属性名称“items”= []下具有相同FaqTopicName的所有项目。

我希望最终得到的数据格式:

{
  topicName: "General", 
  items: { 
         Answer: "test answer",
         Question: "test question",
         SortOrder: 0
        },
        { 
         Answer: "...",
         Question: "...",
         SortOrder: 1
       }
}

以下是我尝试过的内容,但它不正确,也不会通过JavaScriptSerializer()运行:

List<FaqQuestionAnswer> allFaqItemsInSelectedSytem = faqController.GetAllFaqItemsForSystem(out errors);

var groupedData = (from qaItem in allFaqItemsInSelectedSytem
                   group qaItem by qaItem.FaqTopicName
                   into questionsAnswersGroupedDataset
                          select questionsAnswersGroupedDataset).Distinct().ToDictionary(items => new { title = items.Key.ToString(), items = items.ToList() });

在调试器中产生这个:

[0] = {[{title = EBooks,items = System.Collections.Generic.List 1[JPay.Base.FaqQuestionAnswer] }, System.Linq.Lookup 2 + Grouping [System.String,JPay.Base.FaqQuestionAnswer]]}

但是当我通过JSON转换器运行它时会抛出类型错误:

输入'System.Collections.Generic.Dictionary 2[[<>f__AnonymousType0 2 [[System.String,mscorlib,Version = 4.0.0.0,Culture = neutral,PublicKeyToken = XXXXXXXXXXX],[System.Collections.Generic.List { {1}} 2 [[System.String,mscorlib,Version = 4.0.0.0,Culture = neutral,PublicKeyToken = XXXXXXXXXXXXX],[ttt.Base.FaqQuestionAnswer,tttBase,Version = 1.0.6180.30742,Culture = neutral,PublicKeyToken = null字典的序列化/反序列化不支持]],System.Core,Version = 4.0.0.0,Culture = neutral,PublicKeyToken = XXXXXXXXXXXXXXXXX]]',键必须是字符串或对象。

感谢您的帮助。

2 个答案:

答案 0 :(得分:0)

主要问题在于:

.ToDictionary(items => new { title = items.Key.ToString(), items = items.ToList() });

您可能认为自己正在使用Key = items.Key.ToString()Value = items.ToList()定义字典,但实际上您使用的ToDictionary overload具有以下签名:

public static Dictionary<TKey, TSource> ToDictionary<TSource, TKey>(
    this IEnumerable<TSource> source,
    Func<TSource, TKey> keySelector
)

因此,您将结果转换为一个奇怪的字典,其中匿名类型{ string title, IEnumerable<FaqQuestionAnswer> items }作为键,IGrouping<string, IEnumerable<FaqQuestionAnswer>>作为值。

如果你真的需要字典,那么你应该使用this overload代替:

public static Dictionary<TKey, TElement> ToDictionary<TSource, TKey, TElement>(
    this IEnumerable<TSource> source,
    Func<TSource, TKey> keySelector,
    Func<TSource, TElement> elementSelector
)
像这样:

.ToDictionary(g => g.Key, g => g.ToList());

另请注意,Distict之后的GroupBy是多余的。

要获得您所描述的确切格式,您可以使用简单GroupBy与自定义Select

var groupedData = allFaqItemsInSelectedSytem
    .GroupBy(e => e.FaqTopicName)
    .Select(g => new
    {
        topicName = g.Key,
        items = g.Select(e => new { e.Answer, e.Question, e.SortOrder }).ToList()
    }).ToList();

或者如果您更喜欢查询语法:

var groupedData = 
    (from e in allFaqItemsInSelectedSytem
     group e by e.FaqTopicName into g
     select new
     {
        topicName = g.Key,
        items = (from e in g select new { e.Answer, e.Question, e.SortOrder }).ToList()
     }).ToList();

答案 1 :(得分:0)

我最终得到了这个,这给了我需要的结果:

    protected string GetJPayWebsiteFaqTopics()
    {
        // call the FAQ manager
        var faqController = managers.GetFaqManager();
        string errors = string.Empty;
        string result = string.Empty;

        // All items returned from faq manager, 2d collection not grouped into topic dictionaries
        List<FaqQuestionAnswer> allFaqItemsInSelectedSystem = faqController.GetAllFaqItemsForSystem(out errors);

        // Storage for main data, prior to serialization
        List<Dictionary<string, object>> allFaqTopicsAndItems = new List<Dictionary<string, object>>();

        // Group all item Lists together in alike topic related faq items
        IEnumerable<IGrouping<string, FaqQuestionAnswer>> groupedData = from qaItem in allFaqItemsInSelectedSystem
                                                                        group qaItem by qaItem.FaqTopicName;
        // Allow the groupData to get iterated 
        IGrouping<string, FaqQuestionAnswer>[] enumerableGroups = groupedData as IGrouping<string, FaqQuestionAnswer>[] ?? groupedData.ToArray();
        JavaScriptSerializer jsonConverter = new JavaScriptSerializer();

        foreach (var instance in enumerableGroups)
        {
            // Each group of data should have a title for the group, a list of FAQ items
            var items = instance.ToList();

            // Temp storage for each topic and associated faq item data
            Dictionary<string, object> group = new Dictionary<string, object>();

            /**
             * Temp storage for clean faq items stripped of topic level data which has now 
             * been added to the parent node so no longer needed at this level
             */
            List<QuestionAnswerOrderOnly> cleanedItems = new List<QuestionAnswerOrderOnly>();

            // Add the group title
            group.Add("Title", instance.Key);

            // Add the topics display order to the group data 1st item since it is on every item
            group.Add("TopicOrder", items[0].TopicOrder);

            /**
             *  Pull the values that are important for the item only, add it to the group 
             *  Clean up item before recording it to the group it belongs to
             */
            cleanedItems.AddRange(items.Select(item => new QuestionAnswerOrderOnly(item.Question, item.Answer, item.ItemOrder)));

            // Add the clean faqitems collection
            group.Add("Items", cleanedItems);

            // Add this topic group to the result
            allFaqTopicsAndItems.Add(group);
        }

        jsonConverter.MaxJsonLength = Int32.MaxValue;

        try
        {
            result = jsonConverter.Serialize(allFaqTopicsAndItems);
        }
        catch (Exception error)
        {
            result = $"{errors} {error.Message}";
        }

        return result;
    }

并输出以下内容:

{
  topicName: "General", 
  items: { 
         Answer: "test answer",
         Question: "test question",
         SortOrder: 0
        },
        { 
         Answer: "...",
         Question: "...",
         SortOrder: 1
       }
}

我希望这可以帮助处于类似情况的其他人。