修改词典上的重复键值(C#)

时间:2017-02-21 15:42:20

标签: c# dictionary

我有一个要求,我想用字典来存储" 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部分执行此操作。

为相当基本的解释道歉。 许多线程涉及删除字典中的欺骗行为,我理解这不是字典的预期用途。

6 个答案:

答案 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