【问题标题】:Restructure list items into groups将列表项重组为组
【发布时间】:2016-12-03 19:25:40
【问题描述】:

我有一个列表,其中包含这样的项目:

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

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

... (repeated)

我希望重组列表,使其现在包含分组在一个对象内的每个列表项。结果对象将如下所示,并将包含属性名称“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.List1[JPay.Base.FaqQuestionAnswer] }, System.Linq.Lookup2+Grouping[System.String,JPay.Base.FaqQuestionAnswer]]}

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

键入'System.Collections.Generic.Dictionary2[[&lt;&gt;f__AnonymousType02[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=XXXXXXXXXXXX],[System.Collections.Generic.List1[[Base.FaqQuestionAnswer, Version=1.0.6180.30742, Culture=neutral, PublicKeyToken=null]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=XXXXXXXXXXXX]], tttwebsite, Version=1.0.6181.25360, Culture=neutral, PublicKeyToken=null],[System.Linq.IGrouping 2[[System.String,mscorlib,版本=4.0.0.0,文化=中性,PublicKeyToken=XXXXXXXXXXXXX],[ttt.Base.FaqQuestionAnswer,tttBase,版本=1.0.6180.30742,文化=中性,PublicKeyToken=null]],系统.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=XXXXXXXXXXXXXXXXX]]' 不支持字典的序列化/反序列化,键必须是字符串或对象。

感谢您的帮助。

【问题讨论】:

  • 当你说“结果不正确”时,你得到的是什么数据格式?

标签: c# algorithm linq data-structures


【解决方案1】:

主要问题在这里:

.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&lt;FaqQuestionAnswer&gt; items } 作为键和 IGrouping&lt;string, IEnumerable&lt;FaqQuestionAnswer&gt;&gt; 作为值的奇怪字典。

如果你真的需要字典,那么你应该改用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());

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

要获得您描述的确切格式,您可以使用简单的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();

【讨论】:

  • 您好,感谢您的帮助。我也无法将该结果转换为 JSON,这种方式似乎仍然存在相同的问题
【解决方案2】:

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

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

我希望这对处于类似情况的其他人有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-24
    • 1970-01-01
    • 2013-02-22
    • 1970-01-01
    相关资源
    最近更新 更多