简体   繁体   English

字典或列表c#

[英]dictionary or list c#

i got a strange C# programming problem, there is a data retrieval in groups of random lengths of number groups. 我有一个奇怪的C#编程问题,有一组随机长度的数字组的数据检索。 The numbers should be all unique like : 这些数字应该是唯一的,例如:

group[1]{1,2,15}; 
group[2]{3,4,7,33,22,100};
group[3]{11,12,9};

//now there is a routine that adds number to a group
// for the eample just imagine the active group looks like:
// group[active]=(10,5,0)
group[active].add(new_number);

//now if 100 where to be added to the active group
//then active group should be merged to group[2] 
//(as that one allready contained 100)
//And then as a result it would like

group[1]{1,2,15}; 
group[2]{3,4,7,33,22,100,10,5,0};  //10 5 0 added to group[2]
group[3]{11,12,9};

// 100 wasnt added to group[2] since it was allready in there.

If the number to be added is all ready used (not unique) in a previous group. 如果要添加的号码在前一组中已全部就绪使用(非唯一)。 Then i should merge all numbers in the active group towards that previous group, so i dont get double numbers. 然后我应该将活动组中的所有数字合并到前一组,所以我不会得到双数。 So in above example if number 100 was added to the active group. 因此,在上面的示例中,如果将100号添加到活动组。 Then all numbers in the group[active] should be merged into group[2] And then the group[active] should start clean fresh again with no items. 然后, group[active]中的所有数字都应合并到group[2]然后group[active]应该再次开始清新,没有任何项目。 And since 100 was already in group[2] it should not be added double. 并且因为100已经在group[2]所以不应该加倍。

I am not entirely sure on how to deal with this in a proper way. 我不完全确定如何以适当的方式处理这个问题。

As an important criteria here is that it has to work fast. 这里的一个重要标准是它必须快速工作。 i will have around minimal 30 groups (upper-bound unknown might be 2000 or more), and their length on average contains 5 integer numbers, but could be much longer or only 1 number 我将有大约30个组(上限未知可能是2000或更多),它们的长度平均包含5个整数,但可能更长或只有1个数字

I kinda feel that I am reinventing the wheel here. 我觉得我在这里重新发明轮子。

  • I wonder how this problem is called. 我想知道这个问题是如何被调用的。 (does it go by a name, some sorting, or grouping math problem) ?, with a name i might find some articles related to such problems. (它是通过名称,某些排序,还是分组数学问题)?,有了名称,我可能会找到一些与此类问题相关的文章。

  • But maybe its indeed something new, then what would you recommend me? 但也许它确实是新事物,那么你会推荐我什么? Should I use list of lists or a dictionary of lists.. or something else? 我应该使用列表列表还是列表字典..还是其他什么? Somehow the checking if the number is allready present should be done fast. 以某种方式检查数字是否已经存在应该快速完成。

Update i'm thinking along this path now, not sure if its best instead of a single number i use a struct now, it wasnt written in the original question as i was afraid, explaining that would make it too complex 更新我现在正在思考这条路径,不确定它是否最好而不是单个数字我现在使用结构,它不是写在原始问题中,因为我害怕,解释这将使它太复杂

struct data{int ID; int additionalNumber}

Dictionary <int,List<data>> group =new Dictionary<int, List<data>>(); 

update 2 i can step aside from using a struct in here, a lookup list could connect the other data to the proper index. 更新2我可以在这里不使用结构,查找列表可以将其他数据连接到正确的索引。 So this makes it again more close to the original description. 所以这又使它更接近原始描述。

on a side note great answers are given, So far i dont know yet what would work best for me in my situation. 在旁注上给出了很好的答案,到目前为止我还不知道在我的情况下什么对我最有用。

note on selected answer Several answers where given here, I went for the pure dictionary solution. 关于选定答案的注释这里给出了几个答案,我选择了纯字典解决方案。 Just as a note for people in similar problem scenario's i'd still recommend testing, and maybe the others work better for you. 就像在类似问题场景中的人们的注意事项一样,我仍然建议进行测试,也许其他人可以更好地为您工作。 Its just that in my case currently it worked best, the code was also quite short which i liked, and dictionary adds also other handy options for my future coding on this. 它只是在我的情况下目前它工作得最好,代码也很短,我喜欢,字典还为我未来的编码添加了其他方便的选项。

I would go with Dictionary<int, HashSet<int>> , since you want to avoid duplicates and want a fast way to check if given number already exists: 我会使用Dictionary<int, HashSet<int>> ,因为你想避免重复,并希望快速检查给定的数字是否已经存在:

Usage example: 用法示例:

var groups = new Dictionary<int, HashSet<int>>();

// populate the groups
groups[1] = new HashSet<int>(new[] { 1,2,15 });
groups[2] = new HashSet<int>(new[] { 3,4,7,33,22,100 });

int number = 5;
int groupId = 4;

bool numberExists = groups.Values.Any(x => x.Contains(number));

// if there is already a group that contains the number
// merge it with the current group and add the new number
if (numberExists)
{
     var group = groups.First(kvp => kvp.Value.Contains(number));
     groups[group.Key].UnionWith(groups[groupId]);
     groups[groupId] = new HashSet<int>();
}
// otherwise just add the new number
else
{
    groups[groupId].Add(number);
}

I have kept it as easy to follow as I can, trying not to impact the speed or deviate from the spec. 我尽可能地保持它易于遵循,尽量不影响速度或偏离规范。

在此输入图像描述

Create a class called Groups.cs and copy and paste this code into it: 创建一个名为Groups.cs的类,并将此代码复制并粘贴到其中:

using System;
using System.Collections.Generic;

namespace XXXNAMESPACEXXX
{
    public static class Groups
    {
        public static List<List<int>> group { get; set; }

        public static int active { get; set; }


        public static void AddNumberToGroup(int numberToAdd, int groupToAddItTo)
        {
            try
            {
                if (group == null)
                {
                    group = new List<List<int>>();

                }

                while (group.Count < groupToAddItTo)
                {
                    group.Add(new List<int>());

                }

                int IndexOfListToRefresh = -1;

                List<int> NumbersToMove = new List<int>();

                foreach (List<int> Numbers in group)
                {
                    if (Numbers.Contains(numberToAdd) && (group.IndexOf(Numbers) + 1) != groupToAddItTo)
                    {
                        active = group.IndexOf(Numbers) + 1;

                        IndexOfListToRefresh = group.IndexOf(Numbers);

                        foreach (int Number in Numbers)
                        {
                            NumbersToMove.Add(Number);

                        }

                    }

                }

                foreach (int Number in NumbersToMove)
                {
                    if (!group[groupToAddItTo - 1].Contains(Number))
                    {
                        group[groupToAddItTo - 1].Add(Number);

                    }

                }

                if (!group[groupToAddItTo - 1].Contains(numberToAdd))
                {
                    group[groupToAddItTo - 1].Add(numberToAdd);

                }

                if (IndexOfListToRefresh != -1)
                {
                    group[IndexOfListToRefresh] = new List<int>();

                }

            }
            catch//(Exception ex)
            {
                //Exception handling here
            }
        }

        public static string GetString()
        {
            string MethodResult = "";
            try
            {
                string Working = "";

                bool FirstPass = true;

                foreach (List<int> Numbers in group)
                {
                    if (!FirstPass)
                    {
                        Working += "\r\n";

                    }
                    else
                    {
                        FirstPass = false;

                    }

                    Working += "group[" + (group.IndexOf(Numbers) + 1) + "]{";

                    bool InnerFirstPass = true;

                    foreach (int Number in Numbers)
                    {
                        if (!InnerFirstPass)
                        {
                            Working += ", ";

                        }
                        else
                        {
                            InnerFirstPass = false;

                        }

                        Working += Number.ToString();

                    }

                    Working += "};";

                    if ((active - 1) == group.IndexOf(Numbers))
                    {
                        Working += " //<active>";

                    }

                }

                MethodResult = Working;

            }
            catch//(Exception ex)
            {
                //Exception handling here
            }
            return MethodResult;
        }


    }

}

I don't know if foreach is more or less efficient than standard for loops, so I have made an alternative version that uses standard for loops: 我不知道foreach是否比循环的标准效率更高或更低,所以我做了一个使用标准for循环的替代版本:

using System;
using System.Collections.Generic;

namespace XXXNAMESPACEXXX
{
    public static class Groups
    {
        public static List<List<int>> group { get; set; }

        public static int active { get; set; }


        public static void AddNumberToGroup(int numberToAdd, int groupToAddItTo)
        {
            try
            {
                if (group == null)
                {
                    group = new List<List<int>>();

                }

                while (group.Count < groupToAddItTo)
                {
                    group.Add(new List<int>());

                }

                int IndexOfListToRefresh = -1;

                List<int> NumbersToMove = new List<int>();

                for(int i = 0; i < group.Count; i++)
                {
                    List<int> Numbers = group[i];

                    int IndexOfNumbers = group.IndexOf(Numbers) + 1;

                    if (Numbers.Contains(numberToAdd) && IndexOfNumbers != groupToAddItTo)
                    {
                        active = IndexOfNumbers;

                        IndexOfListToRefresh = IndexOfNumbers - 1;

                        for (int j = 0; j < Numbers.Count; j++)
                        {
                            int Number = NumbersToMove[j];

                            NumbersToMove.Add(Number);

                        }

                    }

                }

                for(int i = 0; i < NumbersToMove.Count; i++)
                {
                    int Number = NumbersToMove[i];

                    if (!group[groupToAddItTo - 1].Contains(Number))
                    {
                        group[groupToAddItTo - 1].Add(Number);

                    }

                }

                if (!group[groupToAddItTo - 1].Contains(numberToAdd))
                {
                    group[groupToAddItTo - 1].Add(numberToAdd);

                }

                if (IndexOfListToRefresh != -1)
                {
                    group[IndexOfListToRefresh] = new List<int>();

                }

            }
            catch//(Exception ex)
            {
                //Exception handling here
            }
        }

        public static string GetString()
        {
            string MethodResult = "";
            try
            {
                string Working = "";

                bool FirstPass = true;

                for(int i = 0; i < group.Count; i++)
                {
                    List<int> Numbers = group[i];

                    if (!FirstPass)
                    {
                        Working += "\r\n";

                    }
                    else
                    {
                        FirstPass = false;

                    }

                    Working += "group[" + (group.IndexOf(Numbers) + 1) + "]{";

                    bool InnerFirstPass = true;

                    for(int j = 0; j < Numbers.Count; j++)
                    {
                        int Number = Numbers[j];

                        if (!InnerFirstPass)
                        {
                            Working += ", ";

                        }
                        else
                        {
                            InnerFirstPass = false;

                        }

                        Working += Number.ToString();

                    }

                    Working += "};";

                    if ((active - 1) == group.IndexOf(Numbers))
                    {
                        Working += " //<active>";

                    }

                }

                MethodResult = Working;

            }
            catch//(Exception ex)
            {
                //Exception handling here
            }
            return MethodResult;
        }


    }

}

Both implimentations contain the group variable and two methods, which are; 两个实施都包含组变量和两个方法,它们是; AddNumberToGroup and GetString, where GetString is used to check the current status of the group variable. AddNumberToGroup和GetString,其中GetString用于检查组变量的当前状态。

Note: You'll need to replace XXXNAMESPACEXXX with the Namespace of your project. 注意:您需要将XXXNAMESPACEXXX替换为项目的命名空间。 Hint: Take this from another class. 提示:从另一个班级拿走这个。

When adding an item to your List, do this: 将项目添加到列表时,请执行以下操作:

int NumberToAdd = 10;

int GroupToAddItTo = 2;

AddNumberToGroup(NumberToAdd, GroupToAddItTo);

...or... ...要么...

AddNumberToGroup(10, 2);

In the example above, I am adding the number 10 to group 2. 在上面的示例中,我将数字10添加到组2。

Test the speed with the following: 使用以下方法测试速度:

DateTime StartTime = DateTime.Now;

int NumberOfTimesToRepeatTest = 1000;

for (int i = 0; i < NumberOfTimesToRepeatTest; i++)
{
    Groups.AddNumberToGroup(4, 1);
    Groups.AddNumberToGroup(3, 1);
    Groups.AddNumberToGroup(8, 2);
    Groups.AddNumberToGroup(5, 2);
    Groups.AddNumberToGroup(7, 3);
    Groups.AddNumberToGroup(3, 3);
    Groups.AddNumberToGroup(8, 4);
    Groups.AddNumberToGroup(43, 4);
    Groups.AddNumberToGroup(100, 5);
    Groups.AddNumberToGroup(1, 5);
    Groups.AddNumberToGroup(5, 6);
    Groups.AddNumberToGroup(78, 6);
    Groups.AddNumberToGroup(34, 7);
    Groups.AddNumberToGroup(456, 7);
    Groups.AddNumberToGroup(456, 8);
    Groups.AddNumberToGroup(7, 8);
    Groups.AddNumberToGroup(7, 9);

}

long MillisecondsTaken = DateTime.Now.Ticks - StartTime.Ticks;

Console.WriteLine(Groups.GetString());

Console.WriteLine("Process took: " + MillisecondsTaken);

I think this is what you need. 我想这就是你需要的。 Let me know if I misunderstood anything in the question. 如果我误解了问题中的任何内容,请告诉我。

As far as I can tell it's brilliant, it's fast and it's tested. 据我所知,它很棒,它很快,而且经过测试。

Enjoy! 请享用!

...and one more thing: ...还有一件事:

For the little windows interface app, I just created a simple winforms app with three textboxes (one set to multiline) and a button. 对于小窗口界面应用程序,我刚刚创建了一个简单的winforms应用程序,其中包含三个文本框(一个设置为多行)和一个按钮。

Then, after adding the Groups class above, in the button-click event I wrote the following: 然后,在添加上面的Groups类之后,在按钮单击事件中,我编写了以下内容:

private void BtnAdd_Click(object sender, EventArgs e)
{
    try
    {
        int Group = int.Parse(TxtGroup.Text);

        int Number = int.Parse(TxtNumber.Text);

        Groups.AddNumberToGroup(Number, Group);

        TxtOutput.Text = Groups.GetString();

    }
    catch//(Exception ex)
    {
        //Exception handling here
    }
}

From what I gather you want to iteratively assign numbers to groups satisfying these conditions: 根据我收集的内容,您希望迭代地将数字分配给满足以下条件的组:

  1. Each number can be contained in only one of the groups 每个数字只能包含在一个组中
  2. Groups are sets (numbers can occur only once in given group) 组是集(在给定组中数字只能出现一次)
  3. If number n exists in group g and we try to add it to group g' , all numbers from g' should be transferred to g instead (avoiding repetitions in g ) 如果组g存在数字n并且我们尝试将其添加到组g' ,则应将来自g'所有数字转移到g (避免重复g

Although approaches utilizing Dictionary<int, HashSet<int>> are correct, here's another one (more mathematically based). 虽然使用Dictionary<int, HashSet<int>>是正确的,但这里是另一个(更基于数学)。

You could simply maintain a Dictionary<int, int> , in which the key would be the number, and the corresponding value would indicate the group, to which that number belongs (this stems from condition 1.). 您可以简单地维护一个Dictionary<int, int> ,其中键将是数字,相应的值将指示该数字所属的组(这源于条件1)。 And here's the add routine: 这是添加例程:

//let's assume dict is a reference to the dictionary
//k is a number, and g is a group
void AddNumber(int k, int g)
{
    //if k already has assigned a group, we assign all numbers from g
    //to k's group (which should be O(n))
    if(dict.ContainsKey(k) && dict[k] != g)
    {
        foreach(var keyValuePair in dict.Where(kvp => kvp.Value == g).ToList())
            dict[keyValuePair.Key] = dict[k];
    }
    //otherwise simply assign number k to group g (which should be O(1))
    else
    {
        dict[k] = g;
    }
}

Notice that from a mathematical point of view what you want to model is a function from a set of numbers to a set of groups. 请注意,从数学的角度来看,您想要建模的是从一组数字到一组组的函数。

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

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