繁体   English   中英

字典或列表c#

[英]dictionary or list c#

我有一个奇怪的C#编程问题,有一组随机长度的数字组的数据检索。 这些数字应该是唯一的,例如:

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.

如果要添加的号码在前一组中已全部就绪使用(非唯一)。 然后我应该将活动组中的所有数字合并到前一组,所以我不会得到双数。 因此,在上面的示例中,如果将100号添加到活动组。 然后, group[active]中的所有数字都应合并到group[2]然后group[active]应该再次开始清新,没有任何项目。 并且因为100已经在group[2]所以不应该加倍。

我不完全确定如何以适当的方式处理这个问题。

这里的一个重要标准是它必须快速工作。 我将有大约30个组(上限未知可能是2000或更多),它们的长度平均包含5个整数,但可能更长或只有1个数字

我觉得我在这里重新发明轮子。

  • 我想知道这个问题是如何被调用的。 (它是通过名称,某些排序,还是分组数学问题)?,有了名称,我可能会找到一些与此类问题相关的文章。

  • 但也许它确实是新事物,那么你会推荐我什么? 我应该使用列表列表还是列表字典..还是其他什么? 以某种方式检查数字是否已经存在应该快速完成。

更新我现在正在思考这条路径,不确定它是否最好而不是单个数字我现在使用结构,它不是写在原始问题中,因为我害怕,解释这将使它太复杂

struct data{int ID; int additionalNumber}

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

更新2我可以在这里不使用结构,查找列表可以将其他数据连接到正确的索引。 所以这又使它更接近原始描述。

在旁注上给出了很好的答案,到目前为止我还不知道在我的情况下什么对我最有用。

关于选定答案的注释这里给出了几个答案,我选择了纯字典解决方案。 就像在类似问题场景中的人们的注意事项一样,我仍然建议进行测试,也许其他人可以更好地为您工作。 它只是在我的情况下目前它工作得最好,代码也很短,我喜欢,字典还为我未来的编码添加了其他方便的选项。

我会使用Dictionary<int, HashSet<int>> ,因为你想避免重复,并希望快速检查给定的数字是否已经存在:

用法示例:

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

我尽可能地保持它易于遵循,尽量不影响速度或偏离规范。

在此输入图像描述

创建一个名为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;
        }


    }

}

我不知道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;
        }


    }

}

两个实施都包含组变量和两个方法,它们是; AddNumberToGroup和GetString,其中GetString用于检查组变量的当前状态。

注意:您需要将XXXNAMESPACEXXX替换为项目的命名空间。 提示:从另一个班级拿走这个。

将项目添加到列表时,请执行以下操作:

int NumberToAdd = 10;

int GroupToAddItTo = 2;

AddNumberToGroup(NumberToAdd, GroupToAddItTo);

...要么...

AddNumberToGroup(10, 2);

在上面的示例中,我将数字10添加到组2。

使用以下方法测试速度:

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

我想这就是你需要的。 如果我误解了问题中的任何内容,请告诉我。

据我所知,它很棒,它很快,而且经过测试。

请享用!

...还有一件事:

对于小窗口界面应用程序,我刚刚创建了一个简单的winforms应用程序,其中包含三个文本框(一个设置为多行)和一个按钮。

然后,在添加上面的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
    }
}

根据我收集的内容,您希望迭代地将数字分配给满足以下条件的组:

  1. 每个数字只能包含在一个组中
  2. 组是集(在给定组中数字只能出现一次)
  3. 如果组g存在数字n并且我们尝试将其添加到组g' ,则应将来自g'所有数字转移到g (避免重复g

虽然使用Dictionary<int, HashSet<int>>是正确的,但这里是另一个(更基于数学)。

您可以简单地维护一个Dictionary<int, int> ,其中键将是数字,相应的值将指示该数字所属的组(这源于条件1)。 这是添加例程:

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

请注意,从数学的角度来看,您想要建模的是从一组数字到一组组的函数。

暂无
暂无

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

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