Can we make this more terse with linq? - c#

I am curious if there is a way where I can capture the lower lines (the creation of the dictionary and loop to add values) in the linq statement itself. Right now the select new returns a new anonymous type but I am wondering if there is a way to make it return a Dictionary with all the values pre-populated.
XDocument reader = XDocument.Load("sl.config");
var configValues = from s in reader.Descendants("add") select new { Key = s.Attribute("key").Value, s.Attribute("value").Value };
Dictionary<string, string> Settings = new Dictionary<string, string>();
foreach (var s in configValues)
{
Settings.Add(s.Key, s.Value);
}

Try Enumerable.ToDictionary extension method.
XDocument reader = XDocument.Load("sl.config");
var Settings = reader.Descendants("add")
.ToDictionary(s => s.Attribute("key").Value, s => s.Attribute("value").Value);

var = XDocument.Load("sl.config").Descendants("add").ToDictionary
(x => x.Attribute("key"). Value, x => x.Attribute("value"). Value);

Related

Querying key value in List<string>

I have the following code:
var tuple = new Tuple<string, string>("MyKey", "MyValue");
var list = new List<string>();
var str = tuple.ToString();
list.Add(str);
// str has the value "(MyKey, MyValue)"
I have a predefined object where I need to use a list of strings.
I decided to use a Tuple but I am not sure how I can cast the str value back to a Tuple.
How can I store a key value in a List so that I can use lambda to query it e.g. by the key?
All this code:
var tuple = new Tuple<string, string>("MyKey", "MyValue");
var list = new List<string>();
var str = tuple.ToString();
list.Add(str);
// str has the value "(MyKey, MyValue)"
Could be replaced by a dictionary:
Dictionary<string, string> values = new Dictionary<string, string>();
values.Add("MyKey", "MyValue");
Then you can use linq to query the dictionary if you'd like to do so:
value = values.Where(x => x.ContainsKey("MyKey"));
You can get a list with all the keys as follows:
List<string> keys = values.Keys;
So no need to have a separate list for that.
If you want a list of string with two values separated by a coma, the dictionary will do too:
List<string> keysValues = (from item in values
select item.Key + "," + item.Value).ToList();
Use Dictionary.
var dictionary = new Dictionary<string, string>();
dictionary.Add("myKey", "myVal");
if (dictionary.ContainsKey("myKey"))
dictionary["myKey"] = "myVal1";
I suggest you use a Dictionary. But if you really need to do it this way:
To transform from the string back to Tuple (assuming that the Key itself will never contain a commma+space):
var tuple = Tuple.Create("MyKey", "MyValue");
var list = new List<string>();
var str = tuple.ToString();
list.Add(str);
// str has the value "(MyKey, MyValue)"
Console.WriteLine(str);
int comma = str.IndexOf(", ");
string key = str.Substring(1,comma-1);
string valuee = str.Substring(comma+2,str.Length-key.Length-4);
var tuple2 = Tuple.Create(key, valuee);
// 'tuple2' is now equal to the orignal 'tuple'

Create c# dynamic object from elements of a list

how to convert :
A List :
var list = new List<string>(){"str1","str2"}
to a anonymous object :
var anonymousObject = new {str1 = "str1",str2 = "str2"}
during runtime
You can use the ExpandoObject which will give you the feature of dynamic type.
var list = new List<string>() { "str1", "str2" };
ExpandoObject obj = new ExpandoObject();
var store = (IDictionary<string, object>)obj;
list.ForEach(x => store.Add(x, x));
dynamic lst = obj;
var val = lst.str1; // Test
You can also use extension method represented below (from here).
Because converting list to dynamic object by iterating on items manually can be painful when there is many situations like this in your application.
You can use this extension method like this:
dynamic list = new List<string>() { "str1", "str2" }
.ToDictionary(dd => dd, dd => (object)dd)
.ToExpando();
The extension method:
public static ExpandoObject ToExpando(this IDictionary<string, object> dictionary)
{
var expando = new ExpandoObject();
var expandoDic = (IDictionary<string, object>)expando;
// go through the items in the dictionary and copy over the key value pairs)
foreach (var kvp in dictionary)
{
// if the value can also be turned into an ExpandoObject, then do it!
if (kvp.Value is IDictionary<string, object>)
{
var expandoValue = ((IDictionary<string, object>)kvp.Value).ToExpando();
expandoDic.Add(kvp.Key, expandoValue);
}
else if (kvp.Value is ICollection)
{
// iterate through the collection and convert any strin-object dictionaries
// along the way into expando objects
var itemList = new List<object>();
foreach (var item in (ICollection)kvp.Value)
{
if (item is IDictionary<string, object>)
{
var expandoItem = ((IDictionary<string, object>)item).ToExpando();
itemList.Add(expandoItem);
}
else
{
itemList.Add(item);
}
}
expandoDic.Add(kvp.Key, itemList);
}
else
{
expandoDic.Add(kvp);
}
}
return expando;
}

How to write search query using OR instead of And

I need to write search based on following criteria:
I need to find all records that match values of
key1 OR key2 OR key 3 values...etc
The number of keys and values is variable
List<KeyValuePair<string, string[]>> filterlist = new List<KeyValuePair<string, string[]>>()
{
new KeyValuePair<string, string[]>("Key1", new []{"jay","bloggs"}),
new KeyValuePair<string, string[]>("Key2", new []{"joe","blog","doe"}),
new KeyValuePair<string, string[]>("Key3", new []{"jon","blog"}),
};
Now my implementation
My current implementation does search but all expressions are "AND" instead of OR. I am not sure how to write it.
public class UserSearcher
{
private List<UserProfile> userProfiles;
public UserSearcher()
{
userProfiles = new List<UserProfile>();
}
public static List<UserProfile> SearchProfiles(List<KeyValuePair<string, string[]>> filterList)
{
var list = new List<UserProfile>();
var query = list.AsQueryable();
// search for each pair inside as or
foreach (KeyValuePair<string, string[]> searchPair in filterList)
{
foreach (string searchString in searchPair.Value)
{
string s = searchString;
// search for each item inside as and (has to contains all search strings
query = query.Where(x => x.PersonName.Contains(s));
}
}
return list = query.ToList();
}
}
The full example except db is:
https://gist.github.com/cpoDesign/acf69bc242ed0755597d
Use Predicate Builder - it works well.
So, if I got it right, you want to get back list of UserProfile where PersonName is inside any string[] of KeyValuePair list.
If so, try with this:
public static List<UserProfile> SearchProfiles(List<KeyValuePair<string, string[]>> filterList)
{
var list = new List<UserProfile>();
return list.Where(profile => filterList.Any(kvp => kvp.Value.Contains(profile.PersonName))).ToList();
}
Test example:
public static Expression<Func<T,bool>>
Or<T>(IEnumerable<Expression<Func<T,bool>>> expList){
ParameterExpression pe = Expression.Parameter(typeof(T));
Expression r = null;
foreach(var exp in expList){
r = r == null ? exp : Expression.Or(r,exp);
}
return Expression.Lambda<Func<T,bool>>(r.Body,pe);
}
var orList = new List<Expression<Func<T,bool>>>();
foreach (KeyValuePair<string, string[]> searchPair in filterList)
{
foreach (string searchString in searchPair.Value)
{
string s = searchString;
// search for each item inside as and
// (has to contains all search strings
orList.Add(x => x.PersonName.Contains(s));
}
}
query = query.Where( Or(expList));

hashtable keys from multiple objects in linq

Hashtable mainhash = new Hashtable();
testdata td = new testdata() { value = "td" };
td.hash.Add("1", "tdvalue1");
td.hash.Add("2", "tdvalue2");
td.hash.Add("3", "tdvalue3");
td.hash.Add("4", "tdvalue4");
td.hash.Add("5", "tdvalue5");
testdata td1 = new testdata() { value = "td1" };
td1.hash.Add("1", "td1value1");
td1.hash.Add("2", "td1value2");
td1.hash.Add("3", "td1value3");
td1.hash.Add("4", "td1value4");
td1.hash.Add("5", "td1value5");
testdata td2 = new testdata() { value = "td2" };
td2.hash.Add("1", "td2value1");
td2.hash.Add("2", "td2value2");
td2.hash.Add("3", "td2value3");
td2.hash.Add("4", "td2value4");
td2.hash.Add("5", "td2value5");
testdata td3 = new testdata() { value = "td3" };
td3.hash.Add("1", "td3value1");
td3.hash.Add("2", "td3value2");
td3.hash.Add("3", "td3value3");
td3.hash.Add("4", "td3value4");
td3.hash.Add("5", "td3value5");
testdata td4 = new testdata() { value = "td4" };
td4.hash.Add("1", "td4value1");
td4.hash.Add("2", "td4value2");
td4.hash.Add("3", "td4value3");
td4.hash.Add("4", "td4value4");
td4.hash.Add("5", "td4value5");
mainhash.Add(1, td);
mainhash.Add(2, td1);
mainhash.Add(3, td2);
mainhash.Add(4, td3);
mainhash.Add(5, td4);
how to select all the keys using SelectMany by Linq into one list??
what i need to do in this??
var values = mainhash.Values.Cast<testdata>().Select(x => x.hash)
.SelectMany(x=> x.Keys);
what is wrong in this??
It doesn't know the type to use from Hashtable.Keys.
Try:
var values = mainhash.Values.Cast<testdata>().Select(x => x.hash)
.SelectMany(x => x.Keys.Cast<string>());
But better: use Dictionary<TKey,TValue> instead of Hashtable.
try below query -
var values = mainhash.Values.Cast<testdata>().SelectMany(x => x.hash.Keys.Cast<string>());
But, use dictionary instead of hashtable. It actually reduce the overhead of casting the objects.
hope above code helps you !!

Converting a resource set into dictionary using linq

var rm = new ResourceManager(sometype);
var resourceSet = rm.GetResourceSet(CultureInfo.CurrentUICulture, true, true);
I want to convert the above resource set into dictionary. Currently I'm doing through manually by looping as below.
var resourceDictionary = new Dictionary<string, string>();
foreach (var r in resourceSet)
{
var dicEntry = (DictionaryEntry)r;
resourceDictionary.Add(dicEntry.Key.ToString(), dicEntry.Value.ToString());
}
How I can do achieve that easily using linq?
Try this:
var resourceDictionary = resourceSet.Cast<DictionaryEntry>()
.ToDictionary(r => r.Key.ToString(),
r => r.Value.ToString());
var resourceDictionary = resourceSet.Select(r => (DictionaryEntry) r)
.ToDictionary(dicEntry => dicEntry.Key.ToString(),
dicEntry => dicEntry.Value.ToString());

Categories