I need to create an expression that extract a specific item from a dictionary.
The topic is to put the name of the item to extract inside the Expression.
I'll try to explain it better with an example.
I have this dictionary:
Dictionary<string, object> myDictionary = new Dictionary<string, object>
{
{ "Name", "My first name" },
{ "Age", 42 }
};
I wrote this code to compose an Expression that works with IDictionary:
private Expression<Func<IDictionary<string, object>, string, object>> GetDictionaryExpression()
{
var dictionary = Expression.Parameter(typeof(IDictionary<string, object>), "dict");
var keyParam = Expression.Parameter(typeof(string));
var indexer = typeof(IDictionary<string, object>).GetProperty("Item");
var indexerExpr = Expression.Property(dictionary, indexer, keyParam);
return Expression.Lambda<Func<IDictionary<string, object>, string, object>>(indexerExpr, dictionary, keyParam);
}
Finally, I can write this code:
var x = GetDictionaryExpression();
var y = x.Compile().Invoke(myDictionary, "Name"); // My first name
This code works.
What I need is to create an expression that doesn't need the field "Name" at runtime, but put it inside the Expression.
In other words, something that will let me have something like this:
var x = GetNameFromDictionary(); // <== How to write this method that extract only the 'Name' value from the dictionary?
var y = x.Compile().Invoke(visionRecord); // My first name
Thank you in advance.
Related
I have a list like,
List<string> list = new List<string>();
list.Add("MEASUREMENT");
list.Add("TEST");
I have a dictionary like,
Dictionary<string, string> dict = new Dictionary<string, string>();
dict.Add("BPGA", "TEST");
dict.Add("PPPP", "TEST");
dict.Add("RM_1000", "MEASUREMENT");
dict.Add("RM_2000", "MEASUREMENT");
dict.Add("CDMA", "TEST");
dict.Add("X100", "XXX");
Now, I want to get all matched data from dictionary based on list.
Means, all data from list match with dict value then get new dictionary with following mathched values
Is there any way to achieve this by using lambda expression?
I want result like this.
Key Value
"BPGA", "TEST"
"PPPP", "TEST"
"RM_1000", "MEASUREMENT"
"RM_2000", "MEASUREMENT"
"CDMA", "TEST"
Thanks in advance!
You should be using the dictionary like it is intended to be used i.e. a common key with multiple values for example:
Dictionary<string, List<string>> dict = new Dictionary<string, List<string>>();
Then all you need to do when adding the values is:
dict.Add("TEST", new List<string>() { /*strings go in here*/ });
Then to get all the results from a key like:
List<string> testValues = dict["TEST"];
To make it safe however you should check that the key exists i.e.
if (dict.ContainsKey("TEST"))
{
//Get the values
}
Then to add values to a current key you go do something like:
dict["TEST"].Add("NewValue");
If you insist on keeping the same structure, although I do not recommend it, something like the following will work:
List<string> testKeys = new List<string>();
foreach (var pairs in dict)
{
if (pair.Value == "TEST")
{
testKeys.Add(pair.Key);
}
}
Or even the following LINQ statement:
List<string> testKeys = dict.Where(p => p.Value == "TEST").Select(p => p.Key).ToList();
For a generic query to find the ones from your list use:
List<string> values = dict.Where(p => list.Contains(p.Value)).ToList();
I have this dictionary and tuples set up in SetValue() as below :-
var myDict = new Dictionary<string, Tuple<string, string>>();
private void SetValue()
{
var myTuple1= Tuple.Create("ABC", "123");
var myTuple2= Tuple.Create("DEF", "456");
myDict.Add("One", myTuple1)
myDict.Add("Two", myTuple2)
}
I am trying to retrive the tuple in GetValue() as below :-
private void GetValue()
{
var myTuple = new Tuple<string, string>("",""); //Is this correct way to initialize tuple
if (myDict.TryGetValue(sdsId, out myTuple))
{
var x = myTuple.Item1;
var y = myTuple.Item2;
}
}
My question is whether this is the correct way to initialize tuple while retrieving the same from a dictionary ? Is there a better code?
var myTuple = new Tuple<string, string>("","");
If it's an out parameter, the object doesn't need to be initialized before being used. You should just be able to do:
Tuple<string,string> myTuple;
if (myDict.TryGetValue(sdsId, out myTuple))
{
var x = myTuple.Item1;
var y = myTuple.Item2;
}
You don't need to create an instance for an out parameter. Just declare the local variable as Tuple but don't assign a value.
Tuple<string, string> myTyple;
I have a little problem :) I have a list where some arguments are duplicate. I must remove that. I can't use Distinct becouse i must only see at some fields (not all).I think it's great option to use lambda epxressions.
I have a declaration on my object who i working, not the same but the idea is similar.
var keys = new string[] {"column1", "column2"};
var repeatedValues = new object[] {5, 15};
var values = new List<Dictionary<string, object>>();
//MAKE FAKE DOUBLE
values.Add(new Dictionary<string, object> {
{ "column1", 5 }, { "column2", 15 }, { "column3", "test" },
{ "column4", "test1" } });
for (int i = 0; i < 10; i++)
{
values.Add(new Dictionary<string, object> {
{"column1", i}, {"column2", 10 + i}, "column3", "test"},
{"column4", "test1"}});
}
The keys columns always have the same lenght as repeatedValues - but is changed, some the lenghts is 1, other 2,3,5. Not more than 5
The keys is like primaryKeys on database table. It's quite similar. So we looking for duplicates in "primary keys columns" - i think is a good compare.
We see in that example duplicate is has value 5 in "column1" and values 15 in "column2". How i before say i must remove that, but before i must count repeated items.
I try do code like that (i know the func method awalys fail becouse (object)1 == (object)1 always return false, but it's example :
Expression expression = null;
for (int i = 0; i < keys.Length; i++)
{
Expression<Func<Dictionary<string, object>, bool>> exp = x => x[keys[i]] == repeatedValues[i];
if (expression == null)
expression = exp.Body;
else
expression = Expression.AndAlso(expression, exp.Body);
}
var parameterExpression = Expression.Parameter(typeof (Dictionary<string, object>), "x");
var lamba = Expression.Lambda<Func<Dictionary<string, object>, bool>>(expression, parameterExpression);
var res = lamba.Compile();
var counts = queryLis.Count(res);
But compilator give me a exception
variable 'x' of type 'System.Collections.Generic.Dictionary`2[System.String,System.Object]' referenced from scope '', but it is not defined
It's possible to do this at this way ?
(Not about exception) In other step maybe the expression be asking for example repeatedValues[i] (after for) and it will doesn't know what is it ?
You need to pass the same Expression.Parameter that the original expression is referencing.
Making a new Expression.Parameter with the same name isn't good enough.
I don't know why you're messing with Expression and the like. If I understood you correctly, you're essentially duplicating a relational database situation with each entry of values being a row of data where the column represents the field name. If that's the case, then you might as well take a page from the database book and work off of an index. After your first snippet, you can get at a cleaned-up list like so:
// testing for duplicates
List<Dictionary<string, object>> duplicates = new List<Dictionary<string, object>>();
List<string> index = new List<string>();
foreach (var value in values)
{
List<string> keyValues = new List<string>();
foreach (string key in keys)
{
keyValues.Add(value[key].GetHashCode().ToString());
}
string hash = string.Join(",", keyValues.ToArray());
if (index.Contains(hash))
duplicates.Add(value);
else
index.Add(hash);
}
var cleanList = values.Except(duplicates);
EDIT: altered example so that it puts the hash in the same column order each time.
I want to build a Lambda Expression using Linq Expressions that is able to access an item in a 'property bag' style Dictionary using a String index. I am using .Net 4.
static void TestDictionaryAccess()
{
ParameterExpression valueBag = Expression.Parameter(typeof(Dictionary<string, object>), "valueBag");
ParameterExpression key = Expression.Parameter(typeof(string), "key");
ParameterExpression result = Expression.Parameter(typeof(object), "result");
BlockExpression block = Expression.Block(
new[] { result }, //make the result a variable in scope for the block
Expression.Assign(result, key), //How do I assign the Dictionary item to the result ??????
result //last value Expression becomes the return of the block
);
// Lambda Expression taking a Dictionary and a String as parameters and returning an object
Func<Dictionary<string, object>, string, object> myCompiledRule = (Func<Dictionary<string, object>, string, object>)Expression.Lambda(block, valueBag, key).Compile();
//-------------- invoke the Lambda Expression ----------------
Dictionary<string, object> testBag = new Dictionary<string, object>();
testBag.Add("one", 42); //Add one item to the Dictionary
Console.WriteLine(myCompiledRule.DynamicInvoke(testBag, "one")); // I want this to print 42
}
In the above test method, I want to assign the Dictionary item value i.e. testBag["one"] into the result. Note that I have assigned the passed in Key string into the result to demonstrate the Assign call.
You can use the following to access the Item property of the Dictionary
Expression.Property(valueBag, "Item", key)
Here is the code change that should do the trick.
ParameterExpression valueBag = Expression.Parameter(typeof(Dictionary<string, object>), "valueBag");
ParameterExpression key = Expression.Parameter(typeof(string), "key");
ParameterExpression result = Expression.Parameter(typeof(object), "result");
BlockExpression block = Expression.Block(
new[] { result }, //make the result a variable in scope for the block
Expression.Assign(result, Expression.Property(valueBag, "Item", key)),
result //last value Expression becomes the return of the block
);
I would like to know how to get the name of the property that a method parameter value came from. The code snippet below shows what I want to do:
Person peep = new Person();
Dictionary<object, string> mapping = new Dictionary<object, string>();
mapping[peep.FirstName] = "Name";
Dictionary<string, string> propertyToStringMapping = Convert(mapping);
if (mapping[peep.FirstName] == propertyToStringMapping["FirstName"])
Console.WriteLine("This is my desired result");
private Dictionary<string, string> Convert(Dictionary<object, string> mapping)
{
Dictionary<string, string> stringMapping = new Dictionary<string, string>();
foreach (KeyValuePair<object, string> kvp in mapping)
{
//propertyName should eqal "FirstName"
string propertyName = kvp.Key??????
stringMapping[propertyName] = kvp.Value;
}
return stringMapping;
}
You are not able to do so in this way, since the way it works is that C# evaluates the value of FirstName property by calling its get accessor and passes the value of that to the indexer of the dictionary. Therefore, the way you found out FirstName value is completely lost. Just like the way you evaluate 2 + 2.
If you write, "x = 2 + 2", x will have the value 4 but there will be no way to tell if it was 3 + 1 or 2 + 2 or 5 + (-1) or ... that evaluated to 4.
I think ultimately you will need to store either the PropertyInfo object associated with the property, or the string representation of the property name in you mapping object. The syntax you have:
mapping[peep.FirstName] = "Name";
Would create an entry in the dictionary with a key value equal to the value of the peep.FirstName property, and the Value equal to "Name".
If you store the property name as a string like:
mapping["FirstName"] = "Name";
You could then use reflection to get the "FirstName" property of your object. You would have to pass the "peep" object into the Convert function, however. This seems to be somewhat opposite of what you are wanting to do.
You may also be able to get crazy with Expressions and do something like:
var mapping = new Dictionary<Expression<Action<T>>,string>();
mapping[ p => p.FirstName ] = "Name";
Then in your Convert function you could examine the expression. It would look something like:
private Dictionary<string,string> Convert(Dictionary<Expression<Action<T>>,string> mapping)
{
var result = new Dictionary<string,string>();
foreach(var item in mapping)
{
LambdaExpression ex = item.Key as LambdaExpression;
string propertyName = ((MemberExpression)ex.Body).Member.Name;
string propertyValue = item.Value;
result.Add(propertyName,proeprtyValue);
}
return result;
}
This is more or less off the top of my head, so I may have the expression types off a bit. If there are issues with this implementation let me know and I will see if I can work out a functional example.
I don't know much about C#, but I suppose peep is an enum? As for Java, you could do:
String propertyName = kvp.key.toString()
Maybe there's something similar in C#?
And even if peep isn't a enum: I see no reason why the key should be an arbitrary object? So maybe the solution is exactly to use an enum as type of the key?
Also, I don't know what you're trying to do but usually, I'd not recommend you to convert the enum key to a string. What can you do with a string what you can't do, too, with an enum?