我正在寻找类似于字典的数据结构,该字典将所有相关项的集合返回给密钥。
例如,我会像这样使用它:
var data = new FancyDataStructure();
data.Add(new string[] {"Elizabeth", "Liz", "Betty"});
data.Add(new string[] {"Bob", "Robert", "Rob"});
string[] alternateNames1 = data["Betty"];
string[] alternateNames2 = data["Liz"]
在这个例子中,alternateNames1将是一个包含“Liz”和“Elizabeth”的数组,alternateNames2将是一个包含“Elizabeth”和“Betty”的数组。
我不想重新发明这个,但我找不到任何这种结构的例子。
更新
感谢那些回复过建议的人。许多人建议使用某些版本的Dictionary<string, IEnumerable<string>>
。目前我正在使用这种方法,但它实际上并没有满足要求而不会非常难以维护。每个列表中的每个值都需要能够作为集合中添加到其中的每个其他值的键。
因此,给出以下内容:
data.Add(new string[] {"Elizabeth", "Liz"}
data.Add(new string[] {"Liz", "Betty"}
alternates = data["Betty"];
我希望替补人员现在包含“伊丽莎白”和“利兹”。
看起来我可能只需构建这样的结构以满足我的需求。保持想法即将到来!
布赖恩
答案 0 :(得分:1)
System.Collections.Generic命名空间和System.Collections加载了KeyValue对字典,排序字典,列表对象等等。
System.Collections.Generic.Dictionary<int, string> dic = new Dictionary<int, string>();
dic.Add(1, test);
或字典中的嵌套列表
Dictionary<string, List<string>> dic = new Dictionary<string, List<string>>();
List<string> alternatives = new List<string>();
alternatives.Add("Brenda");
dic.Add("Betty", alternatives);
答案 1 :(得分:1)
只是另一个方向的想法 - 强类型数据集似乎有很多东西。并且序列化为字节数组,它们可以非常快速地移动多维结构化数据。
Iteration和Linq功能是内置的。
对于很多东西来说可能有点过头了,但我有很多地方将整个数据集存储在SQL中的一个varbinary(max)列中。
答案 2 :(得分:1)
您的问题听起来确实是graphing问题。将名称视为节点和集合中的成员资格作为边缘。从这个角度来看,您需要一个能够很好地处理稀疏图形的数据结构,例如adjacency list。当然,这与您使用Dictionary<string, IEnumerable<string>>
的方式类似,但以这种方式思考可能会引导您使用一些有用的实现和算法。
答案 3 :(得分:0)
这样的事情似乎很简单。
var data = new List<string[]>();
data.Add(new string[] {"Elizabeth", "Liz", "Betty"});
data.Add(new string[] {"Bob", "Robert", "Rob"});
var alternateNames1 = data.Where(x =>x.Contains("Betty")).Select(x => x.Where(y => y != "Betty"));
答案 4 :(得分:0)
事实上的alt.net标准在Iesi.Collections中,但基类库在dotnet 3.5或更高版本中只有HashSet<T>
。
我在linq中使用了“group by”这样的子句来轻松删除任意IEnumerable<T>
集合中的重复项,但这并没有给你设置语义。
的HashSet&LT;&GT;接近你想要的。
根据您的要求,我认为现有的东西不会将字符串映射到预先存在的集合;基本上,你必须编写一个类,它采用像StoreAssociations<<T>>(IEnumerable<<T>> names)
这样的方法,将IEnumerable转换为HashSet,并迭代HashSet中的每个项目,以便在IDictionary<string,HashSet<T>>
中为新创建的地图添加一个映射HashSet的。
答案 5 :(得分:0)
我只想使用Dictionary<string, IEnumerable<string>>
类型。要从列表列表构建此结构,您可以使用以下代码:
var alternateNames = new string[][] {
new string[] { "Elizabeth", "Liz", "Betty" },
new string[] { "Bob", "Robert", "Rob" }, };
var altNameLookup =
(
from nameList in alternateNames
from name in nameList
select new {
Name = name, NameList = nameList.Except(new string[] { name } ) }
).ToDictionary(o => o.Name, o => o.NameList);
答案 6 :(得分:0)
你基本上有一个字典,其中多个键映射到相同的值。没有内置的数据结构支持您想要的操作,但它很容易在.NET中表示为Dictionary{string, HashSet{string}}
:
static void AddNames(Dictionary<string, HashSet<string>> map, params string[] names)
{
for (int i = 0; i < names.Length; i++)
{
HashSet<string> value;
if (!map.TryGetValue(names[i], out value))
{
value = new HashSet<string>();
map.Add(names[i], value);
}
for (int j = 0; j < names.Length; j++)
{
value.Add(names[j]);
}
}
}
static void Main(string[] args)
{
Dictionary<string, HashSet<string>> names = new Dictionary<string,HashSet<string>>();
AddNames(names, "Chris", "Christopher");
AddNames(names, "Christina", "Chrissy", "Chris");
HashSet<string> relatedToChris = names["Chris"]; // gets "Chris", "Christina", "Chrissy", "Christopher";
HashSet<string> namesRelatedToChristinia = names["Christina"]; // gets "Christina", "Chrissy", "Chris";
}
您可以将数据结构视为有向图,其中每个节点的边都连接到其相关名称。由于存在n ^ 2个边,因此字典需要O(n ^ 2)时间来插入和存储。它不可能将查找时间缩短到更好。
幸运的是,由于它是作为字典实现的,因此查找仍为O(1)。删除是O(m),其中m是与密钥相关的值的数量。
答案 7 :(得分:0)
一对数据结构怎么样:Dictionary<string, Guid>
和Dictionary<Guid, List<string>>
要添加一对键(a,b)[您可以将更大的添加分解为成对(1 + 2,2 + 3,...),请按以下步骤操作: -
在第一本词典中查找a和b 如果两者都不存在,则创建一个新的Guid并将(a,g)和(b,g)添加到第一个字典和(g,List {a})和(g,List {b})到第二个字典。
如果存在,比如a,从中抓取guid(g)并将另一个(b,g)添加到第一个字典中,并将b添加到第二个字典中[g]的列表末尾。
如果两者都存在并且他们有相同的指导 - 无所事事。
如果两者都存在并且它们有不同的guid你需要合并这两个集//这是大多数其他提议的解决方案似乎都缺失//所以选择一个Guid来消除,从第二个字典中获取它,将字符串列表添加到其他条目,然后删除此条目。最后标记第一个字典中该列表中的所有单词。
要获取所有相关单词,请在第一个词典中查找Guid并从第二个词典中获取列表。
当然,静态递增的长值可能比Guid更好。
答案 8 :(得分:0)
或者,由于List是引用类型,您可以执行以下操作...
Dictionary<string, List<string>> dict = new ...
请按以下步骤操作: -
添加单个关联(a = b){从等价列表中分解}
在词典中查找a和b
如果两者都不存在
dict.Add(a, new List<string>(){a}); dict.Add(b, new List<string>(){b});
如果存在,例如,
var list = dict[a];
list.Add(b);
dict.Add(b, list);
如果两者都存在且列表相同(对象比较),则完成。
如果两者都存在且列表不同:
var list1 = dict[a];
var list2 = dict[b];
list1.AddRange(list2);
dict.Remove(b);
dict.Add(b, list1);
答案 9 :(得分:0)
我写了一些代码,我不知道它有多高效,但我认为它能做到你想要的。
这是你的结构
class FancyDataStructure
{
private IDictionary<string, HashSet<string>> dictionary
= new Dictionary<string, HashSet<string>>();
public void Add(params string[] names)
{
HashSet<string> set = new HashSet<string>(names);
for (int i = 0; i < names.Length; i++)
{
if (!dictionary.ContainsKey(names[i]))
{
dictionary.Add(names[i], set);
}
else
{
HashSet<string> union =
new HashSet<string>(set.Union<string>(dictionary[names[i]]));
set = union;
foreach (string oldName in dictionary[names[i]])
{
dictionary[oldName] = union;
}
for (int j = 0; j < i; j++)
{
if (!dictionary.ContainsKey(names[j]))
{
dictionary.Add(names[j], union);
}
}
}
}
}
public string[] this[string key]
{
get
{
List<string> result = dictionary[key].ToList<string>();
result.Remove(key);
return result.ToArray();
}
}
}
你可以使用它,就像这样
static void Main(string[] args)
{
FancyDataStructure data = new FancyDataStructure();
data.Add("Elizabeth", "Liz");
data.Add("Liz", "Betty");
string[] alternates = data["Betty"];
foreach (var item in alternates)
{
Console.WriteLine(item);
}
}
答案 10 :(得分:-1)
我用这个:
它具有通用的Set&lt; a&gt;输入并实现所有可爱的迭代器,.Contains,.Count等。
答案 11 :(得分:-1)
尝试使用字典,例如:
Dictionary<string, List<string>>
所以字符串键的字典值为List