简体   繁体   English

使用C#对嵌套词典进行排序

[英]Sorting a nested dictionaries using C#

I have a dictionary object with the type like the below. 我有一个字典对象,其类型如下。

Dictionary<string, Dictionary<Roles, Dictionary<Period, List<Product>>>>

The Roles (is an enum) that has "Preparers" & "Approvers" as their items. 具有“准备者”和“批准者”作为项目的角色(是一个枚举)。 Similarly Period is another enum that has "Ahead" & "Past" items. 同样,Period是另一个具有“ Ahead”和“ Past”项目的枚举。

The List holds list of various products. 该列表包含各种产品的列表。

I have items in the following hierarchical structure in the dictionary. 我在字典中具有以下分层结构中的项目。

"Sachin" --> Roles.Preparer --> Period.Past --> Products
"Sachin" --> Roles.Approver --> Period.Ahead --> Products
"Sachin" --> Roles.Approver --> Period.Ahead --> Products
"Sachin" --> Roles.Approver --> Period.Past --> Products

I will have to sort the dictionary in the following order. 我将不得不按以下顺序对字典进行排序。

"Sachin" --> Roles.Preparer --> Period.Ahead --> Products
"Sachin" --> Roles.Approver --> Period.Ahead --> Products
"Sachin" --> Roles.Preparer --> Period.Past --> Products
"Sachin" --> Roles.Approver --> Period.Past --> Products

This structure is required because I will have to iterate through every item and should add as part of the mail. 此结构是必需的,因为我将必须遍历每个项目,并且应将其添加为邮件的一部分。

The actual code is like this. 实际的代码是这样的。

`using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Basics
{
    class Product
    {
        public string Name { get; set; }
        public int Days { get; set; }

    }

    enum Period
    {
        Ahead,
        Past
    }

    enum Roles
    {
        Preparer,
        Approver
    }

    class Program
    {
        static void Main(string[] args)
        {
            DictionaryProcessing(new string[] { "sriram123@yahoo.com", "abhishek321@yahoo.com" });
        }

        private static void DictionaryProcessing(string[] emailIDs)
        {
            List<Product> products = new List<Product>();

            Product product1 = new Product() { Name = "Pencil", Days = 14 };
            Product product2 = new Product() { Name = "Eraser", Days = 2 };
            Product product3 = new Product() { Name = "Geometry Box", Days = 31 };

            products.Add(product1);
            products.Add(product2);
            products.Add(product3);

            Dictionary<string, Dictionary<Roles, Dictionary<Period, List<Product>>>> dict = new Dictionary<string, Dictionary<Roles, Dictionary<Period, List<Product>>>>();

            ///

            foreach (string emailID in emailIDs)
            {

                if (!dict.ContainsKey(emailID))
                    dict.Add(emailID, new Dictionary<Roles, Dictionary<Period, List<Product>>>());

                if (!dict[emailID].ContainsKey(Roles.Preparer))
                    dict[emailID].Add(Roles.Preparer, new Dictionary<Period, List<Product>>());

                if (!dict[emailID][Roles.Preparer].ContainsKey(Period.Ahead))
                    dict[emailID][Roles.Preparer].Add(Period.Ahead, new List<Product>());

                if (!dict[emailID][Roles.Preparer].ContainsKey(Period.Past))
                    dict[emailID][Roles.Preparer].Add(Period.Past, new List<Product>());

                ///

                if (!dict[emailID].ContainsKey(Roles.Approver))
                    dict[emailID].Add(Roles.Approver, new Dictionary<Period, List<Product>>());

                if (!dict[emailID][Roles.Approver].ContainsKey(Period.Ahead))
                    dict[emailID][Roles.Approver].Add(Period.Ahead, new List<Product>());

                if (!dict[emailID][Roles.Approver].ContainsKey(Period.Past))
                    dict[emailID][Roles.Approver].Add(Period.Past, new List<Product>());

                for (int i = 0; i < products.Count; i++)
                {
                    dict[emailID][Roles.Preparer][Period.Ahead].Add(products[i]);
                    dict[emailID][Roles.Preparer][Period.Past].Add(products[i]);
                    dict[emailID][Roles.Approver][Period.Past].Add(products[i]);
                    dict[emailID][Roles.Approver][Period.Ahead].Add(products[i]);
                }


            }
        }
    }
}
`

How can I sort it in this order? 如何按此顺序排序? I am limited to use .NET 2.0 framework. 我仅限于使用.NET 2.0框架。

Dictionaries can not be sorted. 字典无法排序。 They are not lists. 它们不是列表。 Additionally: 另外:

Your structure is bad - a Dictionary can not contain the same key more than once, so the samples you are providing are not even possible to create: 您的结构不好- Dictionary不能多次包含相同的键,因此您提供的样本甚至无法创建:

"Sachin" --> Roles.Preparer --> Period.Past --> Products
"Sachin" --> Roles.Approver --> Period.Ahead --> Products
"Sachin" --> Roles.Approver --> Period.Ahead --> Products
"Sachin" --> Roles.Approver --> Period.Past --> Products

The "outer" dictionary can not contain the key "Sachin" more than once. “外部”词典不能多次包含键“ Sachin”。 The "inner dictionary" can not contain the role Approver more than once and also on the last level, Period.Past/Ahead can not be key more than once. “内部词典”不能多次包含“ Approver ”角色,并且在最后一个级别Period.Past/Ahead上不能多次包含键。

Change your structure to List<T> instead, where T is an appropriate data structure, or, as other have already noted, change to typed datasets now to treat your structure like a table. 相反,将您的结构更改为List<T> ,其中T是适当的数据结构,或者,正如其他人已经指出的那样,现在更改为类型化数据集以将您的结构像表一样对待。

EDIT 编辑
I'm editing my answer now, just to make sure that we all understand what everyone is talking about. 我现在正在编辑我的答案,以确保我们都了解每个人在说什么。

I'm saying, it is not possible for a dictionary to have the same key twice. 我的意思是,字典不可能两次具有相同的键。 So, according to this rule, your cases must be reduced to the following: 因此,根据此规则,您的案件必须减少到以下情况:

"Sachin" --> Roles.Preparer --> Period.Past --> Products
"Sachin" --> Roles.Approver --> Period.Ahead --> Products
"Sachin" --> Roles.Approver --> Period.Past --> Products

Now that we're talking about something that applies to the rules, we can ask "how to sort?". 现在,我们正在讨论适用于规则的内容,我们可以问“如何排序?”。 The answer: you can't. 答案:你不能。 A dictionary is by definition an unordered structure. 根据定义,字典是无序结构。 You can, however, make sure to retrieve the values in a specific order. 但是,您可以确保按特定顺序检索值。 If you want to "sort" the products, so that the Past products always come before the Ahead products, just make sure to use the respective key first. 如果您要对产品进行“分类”,以使“ Past产品始终在“ Ahead产品之前,请确保首先使用相应的密钥。

EDIT 2 编辑2

Just realized this is based on a copy/paste error. 刚刚意识到这是基于复制/粘贴错误。 The data you're talking about should read: 您正在谈论的数据应为:

"Sachin" --> Roles.Preparer --> Period.Ahead --> Products
"Sachin" --> Roles.Preparer --> Period.Past --> Products
"Sachin" --> Roles.Approver --> Period.Past --> Products
"Sachin" --> Roles.Approver --> Period.Ahead --> Products

You said you're using this code to add the items: 您说您正在使用此代码添加项目:

for (int i = 0; i < products.Count; i++)
{
    dict[emailID][Roles.Preparer][Period.Ahead].Add(products[i]);
    dict[emailID][Roles.Preparer][Period.Past].Add(products[i]);
    dict[emailID][Roles.Approver][Period.Past].Add(products[i]);
    dict[emailID][Roles.Approver][Period.Ahead].Add(products[i]);
}

Then you can use similar code to retrieve the items. 然后,您可以使用类似的代码来检索项目。 Given an eMail-ID, the following would get you a list of items in the ordered by "preparer before approver" and "past before ahead": 给定一个电子邮件ID,以下内容将为您提供按“批准前准备”和“先粘贴”顺序排列的项目列表:

List<Product> productsForEMailID = new List<Product>();

productsForEMailID.AddRange(dict[emailID][Roles.Preparer][Period.Past]);
productsForEMailID.AddRange(dict[emailID][Roles.Approver][Period.Past]);
productsForEMailID.AddRange(dict[emailID][Roles.Preparer][Period.Ahead]);
productsForEMailID.AddRange(dict[emailID][Roles.Approver][Period.Ahead]);

The list of products is "sorted". 产品列表是“已排序”的。

You could use another type of key, more suited for this problem. 您可以使用另一种类型的密钥,它更适合此问题。 If you want a quick hack for a SortedDictionary<string, List<Product>> : 如果您想快速破解SortedDictionary<string, List<Product>>

"Sachin#0#0" --> Products
"Sachin#0#1" --> Products
...

Here I assume that the '#' character cannot occur in a name. 在这里,我假设名称中不能出现'#'字符。 The first number represents Roles as Preparer = 0 , Approver = 1 , and the second number represents Period as Ahead = 0 , Past = 1 . 第一个数字代表RolesPreparer = 0 Approver = 1 Preparer = 0Approver = 1 ,第二个数字代表Period ,代表Ahead = 0Past = 1

Or - if you need a slightly more robust solution, I would make something like: 或者-如果您需要一个更强大的解决方案,我将提供以下信息:

public struct Key : IComparable<Key>
{
    public String Name;
    public Roles Role;
    public Period Period;

    public int CompareTo(Key other)
    {
        var c = String.Compare(Name, other.Name, StringComparison.Ordinal);
        if (c != 0) return c;
        c = Role.CompareTo(other.Role);
        if (c != 0) return c;
        return Period.CompareTo(other.Period);
    }
}

... and use a SortedDictionary<Key, List<Product>> . ...并使用SortedDictionary<Key, List<Product>>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM