我遇到了一个奇怪的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 我可以放弃在这里使用结构,查找列表可以将其他数据连接到正确的索引。所以这又使它更接近原始描述。
在附注中给出了很好的答案, 到目前为止,我还不知道在我的情况下什么对我最有效。
关于所选答案的说明 这里给出了几个答案,我选择了纯字典解决方案。 正如针对类似问题场景中的人们的注意事项一样,我仍然建议您进行测试,也许其他人会更好地为您工作。它只是在我的情况下目前它工作得最好,代码也很短,我喜欢,字典还为我未来的编码添加了其他方便的选项。
答案 0 :(得分:5)
我会选择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);
}
答案 1 :(得分:2)
我尽可能地遵循它,尽量不影响速度或偏离规范。
创建一个名为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
}
}
答案 2 :(得分:2)
从我收集的内容中,您希望迭代地为满足这些条件的组分配数字:
n
中存在号码g
,我们会尝试将其添加到群组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;
}
}
请注意,从数学的角度来看,您想要建模的是从一组数字到一组组的函数。