我有一个要求,我想用字典来存储" key = value"然而,现在我需要存储"复制"关键值。
我有一行分隔文本(用竖线字符(" |")分隔,我将其分成一个数组,然后分成一个字典(见下文)
string[] t = rawMessage.Split(new[] { '|', '|' }, StringSplitOptions.RemoveEmptyEntries);
message = t.ToDictionary(s => s.Split('=')[0], s => s.Split('=')[1]);
如果不存在重复项,但我想以插入前调整键值的方式存储重复键,这样可以正常工作。
例如
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部分执行此操作。
为相当基本的解释道歉。 许多线程涉及删除字典中的欺骗行为,我理解这不是字典的预期用途。
答案 0 :(得分:5)
如果您想将多个值与一个键相关联,您可以将该值的一部分作为一个列表:
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);
答案 1 :(得分:3)
您可以使用GroupBy
按键对结果集进行分组,然后使用SelectMany,
使用索引参数Select
方法重载投影所需的键来展平分组:
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);
答案 2 :(得分:2)
您可以使用具有基于集合的值的字典:
Dictionary<string, List<int>>
然后,您可以为所需的工作使用最佳数据结构,但List<>
是一个很好的默认设置。
或者您可以使用Lookup<TKey, TElement>
类,但这不会对值元素进行数组索引:
Lookup<string, int>
支持密钥下的分组(因此可以使用TElement
)。它的文档是here。
或者,仍然可以使用自己的数据结构,但这种情况不太可能需要 - 现有事物的组合可能对您有用。
答案 3 :(得分:0)
嗯..我会在不使用LINQ的情况下找到基本答案。我要做的是制作我自己的ToDictionary
方法,只检查一个密钥是否存在,如果存在,创建新密钥并将其添加到Dictionary
,如下所示:
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;
}
这可以通过扩展方法轻松转换。
答案 4 :(得分:0)
像Adam Houldsworth所说,你可以使用Lookup
。
以下是基于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));
答案 5 :(得分:0)
替代方法是在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 B 0,1,2 D 1 Output