将字符串拆分为字典作为键,列表

时间:2012-09-18 09:42:46

标签: c# c#-4.0

我有一个字符串类型,它将以

格式返回数千条记录

key1,val1,val2,val3,val4,val5:key2,val6,val7,val8,val9,val10:key3,val11,val12,val13,val14,val15

我想将它作为Key,List分配给字典,所以它看起来像

KEY1,[VAL1,VAL2,VAL3,VAL4,val5]

KEY2,[VAL6,val7,的Val8,val9,val10]

KEY3,[VAl11难,val12,val13,val14,val15]

。 。

所有键在字符串中都是唯一的,列表大小对于所有记录都是常量。

目前我正在使用Split并使用

循环每条记录
    //short example string - may contain 1000's
    string newstr = @"key1,val1,val2,val3,val4,val5:key2,val6,val7,val8,val9,val10:key3,val11,val12,val13,val14,val15";

    Dictionary<string, List<string>> mydictionary = new Dictionary<string, List<string>>();
    foreach (string item in newstr.Split(':'))
    {
        List<string> list = new List<string>(item.Split(','));
        mydictionary.Add(list[0], list);        
    }

我的问题是,对于使用C#4.0而不是循环的1000个记录,是否有更高效/更快的方法?

更新:测试了以下各种答案的“正确”时间

enter image description here

static void Main(string[] args)
{
    System.IO.StreamReader myFile =  new System.IO.StreamReader(@"C:\Users\ooo\Desktop\temp.txt");
    string newstr = myFile.ReadToEnd();
    myFile.Close();

    TimeSpan ts;
    TimeSpan te;
    Stopwatch stopWatch = new Stopwatch();
    stopWatch.Start();


    ts = stopWatch.Elapsed;
    Dictionary<string, List<string>> mydictionary = new Dictionary<string, List<string>>();
    foreach (string item in newstr.Split(':'))
    {
        List<string> list = new List<string>(item.Split(','));
        mydictionary.Add(list[0], list);
    }
    te = stopWatch.Elapsed;
    Console.WriteLine("MyTime: " + (te - ts).ToString());



    ts = stopWatch.Elapsed;
    var result = newstr.Split(':')
         .Select(line => line.Split(','))
         .ToDictionary(bits => bits[0],
                       bits => bits.Skip(1).ToList());
    te = stopWatch.Elapsed;
    Console.WriteLine("JonSkeet: " + (te - ts).ToString());


    ts = stopWatch.Elapsed;
    string[] keysAndValues = newstr.Split(':');
    var newdictionary = new Dictionary<string, List<string>>(keysAndValues.Length);
    foreach (string item in keysAndValues)
    {
        List<string> list = new List<string>(item.Split(','));
        newdictionary.Add(list[0], list);
    }
    te = stopWatch.Elapsed;
    Console.WriteLine("Joe: " + (te - ts).ToString());


    Console.WriteLine("Records: " + mydictionary.Count.ToString());


    stopWatch.Stop();
}

3 个答案:

答案 0 :(得分:3)

以下内容可能更快,因为构建的Dictionary具有避免重新分配所需的容量:

//short example string - may contain 1000's     
string newstr = ...;

string[] keysAndValues = newstr.Split(':');
var mydictionary = new Dictionary<string, List<string>>(keysAndValues.Length);
foreach (string item in keysAndValues)     
{         
    List<string> list = new List<string>(item.Split(','));         
    mydictionary.Add(list[0], list);
    // remove key from list to match Jon Skeet's implementation
    list.RemoveAt(0);
} 

比Jon Skeet的LINQ版本更不易读。

答案 1 :(得分:2)

听起来你想要这样的东西:

var result = text.Split(':')
                 .Select(line => line.Split(','))
                 .ToDictionary(bits => bits[0],
                               bits => bits.Skip(1).ToList());

它可能不再是高效,当然......你有没有测量到它需要?如果你只为“成千上万”的记录做这个,我希望它能在眨眼之间完成。此外,我希望在此代码出现之前,任何IO(网络,磁盘)都是瓶颈。

来自你的评论:

  

它实际上非常快而且不是瓶颈,但如果有更快的替代方案,我总是尽量避免循环

不要那样做。瞄准执行该作业的最简单的代码,然后检查它是否执行足够。我个人更喜欢我的基于LINQ的代码,但你现有的代码也很好。任何更快的替代方案很可能最终难以编写,读取和维护。如果收益微不足道,你为什么要去努力?

请注意,我的代码将密钥作为列表中的第一个值 - 它与规范匹配,但不符合示例代码。

答案 2 :(得分:2)

根据LINQ解决方案(如@ JonSkeet)运行您发布的代码,表明LINQ大约是当前方法为超过1000条记录所用的时间的两倍。

因此,回答你的问题:

  

对于使用C#4.0而不是循环的1000个记录,有更高效/更快的方法吗?

我会说不。

基准测试代码:

 var value = "key{0},val1,val2,val3,val4,val5:";
 string newstr = "";
 for (int i = 0; i <= 1000; i++)
 {
     newstr += String.Format(value, i + 1);
 }

 var sw = new System.Diagnostics.Stopwatch();
 sw.Start();
 Dictionary<string, List<string>> mydictionary = new Dictionary<string, List<string>>();
 foreach (string item in newstr.Split(':'))
 {
     List<string> list = new List<string>(item.Split(','));
     mydictionary.Add(list[0], list);
 }
 sw.Stop();
 Console.WriteLine("Looping time: " + sw.Elapsed.ToString());
 sw.Reset();
 sw.Start();
 var result = newstr.Split(':')
                    .Select(line => line.Split(','))
                    .ToDictionary(bits => bits[0],
                                  bits => bits.Skip(1).ToList());
 sw.Stop();
 Console.WriteLine("LINQ time: " + sw.Elapsed.ToString());
 Console.ReadKey();