Split a string into a tuple using LINQ?
For a string like "name:Dave" that I would like to convert to Tuple<string,string> , is there an easy way to do this inline using LINQ, instead of getting the array first, then parsing it?
I am parsing some configuration data from my app.config file as follows:
<Data> <add key="John" value="instrument:guitar"/> <add key="Paul" value="instrument:bass"/> <add key="George" value="instrument:guitar"/> <add key="Ringo" value="instrument:drums"/> </Data> What I want to convert to Dictionary<string,tuple<string,string>> (I know this is an odd data structure!)
Starting with some code:
var x = ((ConfigurationManager.GetSection("Data") as Hashtable)) .Cast<System.Collections.DictionaryEntry>() .ToDictionary(n => n.Key.ToString(), n => something(n.Value.ToString().Split(':'))); I wondered if there is a neat LINQ way for this in a string, and not for writing utility functions, to get from a String.Split array into one Tuple?
var source = new Dictionary<string, string>(){ { "John", "instrument:guitar" } }; var tuple = source.Select(x => new { key = x.Key, values = x.Value.Split(':') }).Select(y => new Tuple<string, string>(y.key, y.values[1])).ToList(); Your string is basically XML , so I'll just System.Xml this using the XmlDocument namespace from System.Xml . Then you can simply use GetElementsByTagName , because all the values you want to get have the same tag ( <add /> ), and then just use it to create such a dictionary:
string @xml = @"<Data> <add key=""John"" value=""instrument:guitar""/> <add key=""Paul"" value=""instrument:bass""/> <add key=""George"" value=""instrument:guitar""/> <add key=""Ringo"" value=""instrument:drums""/> </Data>"; XmlDocument doc = new XmlDocument(); doc.LoadXml(@xml); var dict = new Dictionary<string, Tuple<string, string>>(); doc.GetElementsByTagName("add") .OfType<XmlElement>() .Select(element => { string key = element.Attributes["key"].Value; string[] value = element.Attributes["value"].Value.Split(':'); dict.Add(key, new Tuple<string, string>(value[0], value[1])); return dict.Last(); }); return dict; Who can be shortened like this:
XmlDocument doc = new XmlDocument(); doc.LoadXml(@xml); Dictionary<string, Tuple<string, string>> dict = doc.GetElementsByTagName("add") .OfType<XmlElement>() .Select(element => new Tuple<string, string[]>(element.Attributes["key"].Value, element.Attributes["value"].Value.Split(':'))) .ToDictionary(element => element.Item1, element => new Tuple<string, string>(element.Item2[0], element.Item2[1])); return dict; Or even shorter:
XmlDocument doc = new XmlDocument(); doc.LoadXml(@xml); Dictionary<string, Tuple<string, string>> dict = doc.GetElementsByTagName("add") .OfType<XmlElement>() .ToDictionary(element => element.Attributes["key"].Value, element => new Tuple<string, string>(element.Attributes["value"].Value.Split(':')[0], element.Attributes["value"].Value.Split(':')[1])); return dict; EDIT: (after editing the question)
You can use the System.Configuration library that contains the ConfigurationManager object and do it like this:
ConfigurationManager.AppSettings.AllKeys.ToDictionary( key => key, key => new Tuple<string, string>( ConfigurationManager.AppSettings[key].Split(':')[0], ConfigurationManager.AppSettings[key].Split(':')[1] ) ); But you have to make sure that app.config contains only those keys that you want to process using this method. If you try to process a string that looks like <add key="Willy" value="noinstrument" /> , this method will break.