修改字典(C#)条目上的重复键值
我需要使用字典来存储“key=value”对,但是现在我需要存储“replicate”键值 我有一行带分隔符的文本(用管道字符(“|”)分隔),我将其拆分为一个数组,然后再拆分为一个字典(见下文) 如果不存在重复项,这可以正常工作,但我希望以一种在插入前调整键值的方式存储重复的键 范例修改字典(C#)条目上的重复键值,c#,dictionary,C#,Dictionary,我需要使用字典来存储“key=value”对,但是现在我需要存储“replicate”键值 我有一行带分隔符的文本(用管道字符(“|”)分隔),我将其拆分为一个数组,然后再拆分为一个字典(见下文) 如果不存在重复项,这可以正常工作,但我希望以一种在插入前调整键值的方式存储重复的键 范例 A=1|B=2|C=3|D=4|D=5|D=5 我希望将键值调整为以下值: A=1 B=2 C=3 D=4 D[1]=5 D[2]=5 然后我可以取出第二个和第三个“D”项的条目,因为它们有一个新的键值 每个
A=1|B=2|C=3|D=4|D=5|D=5
我希望将键值调整为以下值:
A=1
B=2
C=3
D=4
D[1]=5
D[2]=5
然后我可以取出第二个和第三个“D”项的条目,因为它们有一个新的键值
每个副本都是一个unqiue记录,因此我希望能够按照输入的顺序进行引用。例如,第四个条目将是D[4]。关于对所有值使用相同键值的建议可能会/将令人困惑,并且我可能最终提取错误的信息(但请记住)
我希望避免事先遍历数组,并想知道是否有人知道我可以在上面代码的ToDictionary部分执行此操作的方法
为这相当基本的解释道歉。
许多线程处理删除字典中的重复项,我知道这不是字典的预期用途。如果要将多个值与一个键关联,可以将该对的值部分设置为一个列表:
var dict = new Dictionary<char, List<int>>();
char key = 'D';
int value = 5;
if (!dict.ContainsKey(key))
dict[key] = new List<int>();
dict[key].Add(value);
var dict=newdictionary();
字符键='D';
int值=5;
如果(!dict.ContainsKey(键))
dict[key]=新列表();
dict[键]。添加(值);
您可以使用具有基于集合的值的词典:
Dictionary<string, List<int>>
字典
然后,您可以为所需的作业使用最佳的数据结构,但是List
是一个很好的默认值
或者您可以使用Lookup
类,但这不会为值元素提供数组索引:
Lookup<string, int>
查找
它支持键下的分组(因此可枚举的TElement
)
或者,也可以滚动您自己的数据结构,但这不太可能是必需的-现有内容的组合可能会对您足够好。您可以使用
GroupBy
按键对结果集进行分组,然后使用SelectMany展平分组,使用S投影所需的键选择带有索引参数的方法重载:
var message = t
.Select(s => s.Split('='))
.GroupBy(s => s[0], s => s[1])
.SelectMany(g => g.Select((v, i) => new
{
Key = i == 0 ? g.Key : g.Key + "[" + i + "]",
Value = v
}))
.ToDictionary(e => e.Key, e => e.Value);
嗯..我将给出一个基本答案,不使用LINQ。我要做的是创建自己的ToDictionary
方法,只需检查一个键是否存在,如果存在,则创建新键并将其添加到字典中,类似这样:
public Dictionary<string,string> ToDictionary(string[] t)
{
Dictionary<string, string> dict = new Dictionary<string, string>();
foreach (string s in t)
{
string[] reg = s.Split('=');
int i = 1;
while (dict.ContainsKey(reg[0]))
{
if (!reg[0].Contains('['))
reg[0] = reg[0] + "[" + i.ToString() + "]";
else
reg[0] = reg[0].Replace((i - 1).ToString(), i.ToString());
i++;
}
dict.Add(reg[0], reg[1]);
}
return dict;
}
公共字典目录(字符串[]t)
{
Dictionary dict=新字典();
foreach(t中的字符串s)
{
字符串[]reg=s.Split('=');
int i=1;
while(dict.ContainsKey(reg[0]))
{
如果(!reg[0]。包含('['))
reg[0]=reg[0]+“[”+i.ToString()+“]”;
其他的
reg[0]=reg[0]。替换((i-1).ToString(),i.ToString());
i++;
}
dict.Add(reg[0],reg[1]);
}
返回命令;
}
这可以很容易地用扩展方法进行转换。就像Adam Houldsworth说的那样,您可以使用查找
下面是一个基于亚当·霍尔德斯沃思答案的片段
var str = @"A=1|B=2|C=3|D=4|D=5|D=5";
string[] t = str.Split(new[] { '|', '|' }, StringSplitOptions.RemoveEmptyEntries);
var message = t.ToLookup(s => s.Split('=')[0], s => Convert.ToInt32(s.Split('=')[1]));
var res = message.ToDictionary(i=>i.Key, x=>x.LastOrDefault());
编辑:
在再次阅读您的问题后,我理解您也需要D=4的值
var res = message.SelectMany(i => i.Select((x, y) => new
{
Key = i.Key,
Value = x
})).GroupBy(q=>q.Value)
.SelectMany(x=>x.ToLookup(xx=>xx.Key, xx=>xx.Value));
另一种方法是在System.Collections.Specialized中使用NameValueCollection。NameValueCollection的有趣之处在于,如果同一个键有重复的值,它会将这些值保留在同一个键中,作为逗号分隔的值。这样键将是相同的,但这些值可能必须将其分隔开。
下面给出了一个快速示例和输出
class Program
{
static void Main(string[] args)
{
NameValueCollection col = new NameValueCollection();
col.Add("A", "1");
col.Add("A", "2");
col.Add("B", "0");
col.Add("B", "1");
col.Add("B", "3");
col.Add("D", "1");
foreach (string key in col.AllKeys)
{
Console.WriteLine(key + " " + col[key] + "\n");
}
Console.ReadKey();
}
}
输出
A 1,2
b0,1,2
D 1
您必须设计自己的数据结构来跟踪重复项。或者按照@itsme86所说的去做。但这取决于您希望如何检索这些信息。词典的使用者如何知道他们想要第一个D
键还是第二个?Quantic-第一个条目是D,第二个是D[1],第三个是D[2]以此类推,“[]”的格式就是唯一地插入密钥。然后他们会输入他们想看到的密钥。这听起来是一个很好的解决方案。以前做过很多次。谢谢你的评论。问题是每个重复的密钥都是一个单独的记录,所以将它们聚在一起意味着我将失去根据unqiue值提取数据的能力。我将更详细地更新这个问题。@Arclight我不确定我是否理解。你可以只做dict['D'][1]
获取第二个D条目。@Fabio很公平。我将把它留给您的评论来添加-OP除了能够按照插入顺序索引之外,实际上并没有太多关于用法的说明,而Lookup
实际上并没有提供任何一种方法,但我感觉这是一个XY问题。
class Program
{
static void Main(string[] args)
{
NameValueCollection col = new NameValueCollection();
col.Add("A", "1");
col.Add("A", "2");
col.Add("B", "0");
col.Add("B", "1");
col.Add("B", "3");
col.Add("D", "1");
foreach (string key in col.AllKeys)
{
Console.WriteLine(key + " " + col[key] + "\n");
}
Console.ReadKey();
}
}