Custom compare dictionaries using LINQ - linq

I've two dictionaries as following:
//Dictionary 1:
Dictionary<string, string> dict1 = new Dictionary<string, string>();
dict1 .Add("key1", "value1");
dict1 .Add("key2", "value2");
dict1 .Add("key3", "value3");
//Dictionary 2 :
Dictionary<string, string> request = new Dictionary<string, string>();
request.Add("key1", "value1");
request.Add("key2", "value2");
I need to compare above two dictionaries using LINQ query with condition:
All keys in dict2 should match with keys in dict1
The matched keys should have equivalent value
I tried creating a extension method on dictionary, but it returns false as dict1 contains one extra pair.
public static class DictionaryExtension
{
public static bool CollectionEquals(this Dictionary<string, string> collection1,
Dictionary<string, string> collection2)
{
return collection1.ToKeyValue().SequenceEqual(collection2.ToKeyValue());
}
private static IEnumerable<object> ToKeyValue(this Dictionary<string, string> collection)
{
return collection.Keys.OrderBy(x => x).Select(x => new {Key = x, Value = collection[x]});
}
}

You can just use the All() extension method to test if all elements of a collection satisfy a certain condition.
var dict1 = new Dictionary<string, string>
{
{"key1", "value1"},
{"key2", "value2"},
{"key3", "value3"}
};
var dict2 = new Dictionary<string, string>
{
{"key1", "value1"},
{"key2", "value2"}
};
dict2.All(kvp => dict1.Contains(kvp)); // returns true
Another (probably faster, but not so funky) approach is to do the intersection of two hashsets:
var h1 = new HashSet<KeyValuePair<string, string>>(dict1);
var h2 = new HashSet<KeyValuePair<string, string>>(dict2);
h1.IntersectWith(h2);
var result = (h1.Count == h2.Count); // contains true

Related

Lucene.net Negation clause is not working

I am very much new to Lucene.net and though I am not able to achieve basic functionality i.e. Not in.
My requirement is to search "road?construction" without "Works" word.
e.g.
Main Road Construction Works -- Invalid
Road Construction And Maintenance Services -- Valid (Doesn't contains word Works)
Please refer my code below.
string searchQuery = "\"road?construction\"*";
BooleanQuery query2 = new BooleanQuery();
Query query;
try
{
query = parser.Parse(searchQuery.Trim());
}
catch (ParseException)
{
query = parser.Parse(QueryParser.Escape(searchQuery.Trim()));
}
query2.Add(query,Occur.SHOULD);
query2.Add(new BooleanClause(new TermQuery (new Term("Name", "Works")), Occur.MUST_NOT));
This still gets both above mentioned record in to search result. I wish to cut invalid record(first).
Here is the result query generated in backend.
Please suggest workaround.
Thanks in advanced.
Not sure why your putting wildcard characters into the phrase. If you're looking for "road construction" then that's all you need. If you are looking to allow some variations then maybe a "slop phrase" is what you need ie. "road construction"~2. The number part allows for n "operations" like n additional words inbetween.
Here's a set of tests that show your examples (TestExpr2, TestExpr3) and some working variations (TestExpr1 and TestQuery).
Hope this helps
[TestClass]
public class UnitTest7
{
[TestMethod]
public void TestExpr1()
{
TestExpr("\"road construction\" -works");
}
[TestMethod]
public void TestExpr2()
{
TestExpr("\"road?construction\"* -works");
}
[TestMethod]
public void TestExpr3()
{
TestExpr(QueryParser.Escape("\"road?construction\"* -works"));
}
private void TestExpr(string expr)
{
var writer = CreateIndex();
Add(writer, "Main Road Construction Works");
Add(writer, "Road Construction And Maintenance Services");
writer.Flush(true, true, true);
var searcher = new IndexSearcher(writer.GetReader());
var result = Search(searcher, expr);
Assert.AreEqual(1, result.Count);
Assert.IsTrue(result.Contains("Road Construction And Maintenance Services"));
writer.Dispose();
}
[TestMethod]
public void TestQuery()
{
var writer = CreateIndex();
Add(writer, "Main Road Construction Works");
Add(writer, "Road Construction And Maintenance Services");
writer.Flush(true, true, true);
var searcher = new IndexSearcher(writer.GetReader());
var query = new BooleanQuery();
var p = new PhraseQuery();
p.Add(new Term("name", "road"));
p.Add(new Term("name", "construction"));
query.Add(p, Occur.MUST);
query.Add(new TermQuery(new Term("name", "works")), Occur.MUST_NOT);
var result = Search(searcher, query);
Assert.AreEqual(1, result.Count);
Assert.IsTrue(result.Contains("Road Construction And Maintenance Services"));
writer.Dispose();
}
private List<string> Search(IndexSearcher searcher, string expr)
{
var analyzer = new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_30);
var queryParser = new QueryParser(Lucene.Net.Util.Version.LUCENE_30, "name", analyzer);
var query = queryParser.Parse(expr);
return Search(searcher, query);
}
private List<string> Search(IndexSearcher searcher, Query query)
{
var collector = TopScoreDocCollector.Create(10, true);
searcher.Search(query, collector);
var result = new List<string>();
var matches = collector.TopDocs().ScoreDocs;
foreach (var item in matches)
{
var id = item.Doc;
var doc = searcher.Doc(id);
result.Add(doc.GetField("name").StringValue);
}
return result;
}
IndexWriter CreateIndex()
{
var directory = new RAMDirectory();
var analyzer = new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_30);
var writer = new IndexWriter(directory, analyzer, new IndexWriter.MaxFieldLength(1000));
return writer;
}
void Add(IndexWriter writer, string text)
{
var document = new Document();
document.Add(new Field("name", text, Field.Store.YES, Field.Index.ANALYZED));
writer.AddDocument(document);
}
}

How to get a list of enum values and descriptions?

I have the following enum:
public enum AlertSeverity
{
[Description("Informative")]
Informative = 1,
[Description("Low risk")]
LowRisk = 2,
[Description("Medium risk")]
MediumRisk = 3,
[Description("High risk")]
HighRisk = 4,
Critical = 5
}
and I want to get a List<KeyValuePair<string, int>> of all the description / names and values,
so I tried something like this:
public static List<KeyValuePair<string, int>> GetEnumValuesAndDescriptions<T>() where T : struct
{
var type = typeof(T);
if (!type.IsEnum)
throw new InvalidOperationException();
List<KeyValuePair<string, int>> lst = new List<KeyValuePair<string, int>>();
foreach (var field in type.GetFields())
{
var attribute = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) as DescriptionAttribute; // returns null ???
if (attribute != null)
lst.Add(new KeyValuePair<string, int>(attribute.Description, ((T)field.GetValue(null)).ToInt()));
else
lst.Add(new KeyValuePair<string, int>(field.Name, ((T)field.GetValue(null)).ToInt())); // throws exception: "Non-static field requires a target" ???
}
return lst;
}
I don't know why but the attribute var returns null and the field.Name throws exception "Non-static field requires a target"
This should work:
public static List<KeyValuePair<string, int>> GetEnumValuesAndDescriptions<T>()
{
Type enumType = typeof (T);
if (enumType.BaseType != typeof(Enum))
throw new ArgumentException("T is not System.Enum");
List<KeyValuePair<string, int>> enumValList = new List<KeyValuePair<string, int>>();
foreach (var e in Enum.GetValues(typeof(T)))
{
var fi = e.GetType().GetField(e.ToString());
var attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
enumValList.Add(new KeyValuePair<string, int>((attributes.Length > 0) ? attributes[0].Description : e.ToString(), (int)e));
}
return enumValList;
}

How to join different datasources using Linq to Objects

I need to join different datasources in runtime using linq to objects, but my datasources types are unknown. So, I canĀ“t use Join directly.
I have a Dictionary containing my datasources, and that is how far I got:
public virtual IEnumerable DataSource { get; set; }
public virtual void MergeDataSources()
{
var outerType = System.Type.GetType(DataSources.Keys.First());
DataSource = Cast(DataSources[DataSources.Keys.First()], outerType);
foreach (var typeName in DataSources.Keys.Skip(1))
outerType = Join(outerType, System.Type.GetType(typeName), new[] { "CodigoCliente" }, new[] { "CodigoCliente" });
}
private IEnumerable Cast(IEnumerable datasource, Type type)
{
return typeof(Enumerable)
.GetMethod("Cast")
.MakeGenericMethod(type)
.Invoke(null, new object[] { datasource }) as IEnumerable;
}
private Type Join(Type outerType, Type innerType, string[] outerKey, string[] innerKey)
{
var outerKeySelector = GetKeySelector(outerType, outerKey);
var innerKeySelector = GetKeySelector(innerType, innerKey);
var resultSelector = Expression.Lambda(
null, // <<<<<<------- MISSING!!!
Expression.Parameter(outerType),
Expression.Parameter(innerType));
DataSource = typeof(Enumerable)
.GetMethod("Join")
.MakeGenericMethod(outerType, innerType, typeof(string), typeof(IEnumerable))
.Invoke(null, new object[] { DataSource, DataSources[innerType.AssemblyQualifiedName], outerKeySelector, innerKeySelector, resultSelector }) as IEnumerable;
return null; // <<<<<<------- MISSING!!!
}
The last thing that I need is: each type joined must be a property of resulting object. Example: new { Type1 = some_Obj_Of_Type1, Type2 = some_Obj_Of_Type2 }
EDIT:
I added a DataSource property, that represents my merged collection
You could use Reflection.Emit to create the return type dynamically, take a look here - How to create LINQ Expression Tree with anonymous type in it.
To match your example:
private Type Join(Type outerType, Type innerType, string[] outerKey, string[] innerKey)
{
var outerKeySelector = GetKeySelector(outerType, outerKey);
var innerKeySelector = GetKeySelector(innerType, innerKey);
Dictionary<string, Type> dynamicFields = new Dictionary<string, Type>
{
{ outerType.Name, outerType },
{ innerType.Name, innerType }
};
Dictionary<string, ParameterExpression> parameters = new Dictionary<string, ParameterExpression>
{
{ outerType.Name, Expression.Parameter(outerType) },
{ innerType.Name, Expression.Parameter(innerType) }
};
Type dynamicType = LinqRuntimeTypeBuilder.GetDynamicType(dynamicFields);
var resultSelector = Expression.Lambda(
Expression.MemberInit(
Expression.New(
dynamicType.GetConstructor(Type.EmptyTypes)),
dynamicType.GetFields().Select(f => Expression.Bind(f, parameters[f.Name]))),
parameters.Values)
.Compile();
DataSource = typeof(Enumerable)
.GetMethods().Where(m => m.Name == "Join" && m.GetParameters().Length == 5).First()
.MakeGenericMethod(outerType, innerType, typeof(string), typeof(object))
.Invoke(null, new object[] { DataSource, DataSources[innerType.AssemblyQualifiedName], outerKeySelector, innerKeySelector, resultSelector }) as IEnumerable;
return dynamicType;
}

Populate dictionary from enum

I have the following enum:
public enum LifeCycle
{
Pending = 0,
Approved = 1,
Rejected = 2,
}
And I want to create
Dictionary<int, string> LifeCycleDict;
from the enum value and its toString
Is there a way to do it with linq?
(The equivelant to java's enum.values )
Thanks.
Dictionary<int, string> LifeCycleDict = Enum.GetNames(typeof(LifeCycle))
.ToDictionary(Key => (int)Enum.Parse(typeof(LifeCycle), Key), value => value);
OR
Dictionary<int, string> LifeCycleDict = Enum.GetValues(typeof(LifeCycle)).Cast<int>()
.ToDictionary(Key => Key, value => ((LifeCycle)value).ToString());
OR
Dictionary<int, string> LifeCycleDict = Enum.GetValues(typeof(LifeCycle)).Cast<LifeCycle>()
.ToDictionary(t => (int)t, t => t.ToString());

Update a Dictionary value using Linq

I will call AnalyseLinqUpdate()
I think code itself clear..
I have to find behavior for each dictionary value and replace the value with the behavior I get from the method 'GiveBehavior'
void AnalyseLinqUpdate()
{
Dictionary<string, string> rawCollection = new Dictionary<string, string>();
rawCollection.Add("PT-1", "PTC-1");
rawCollection.Add("PT-2", "PTC-1");
rawCollection.Add("PT-3", "PTC-2");
rawCollection.Add("PT-4", "PTC-2");
rawCollection.Add("PT-5", "PTC-3");
rawCollection.Add("PT-6", "PTC-3");
//update here
// call GiveBehavior("PTC-1");
//returns a string that needs to be updated in place of "PTC-1"
}
string GiveBehavior(string ptc)
{
StringComparison ignoreCase = StringComparison.OrdinalIgnoreCase;
ptc = ptc.Trim();
if (ptc.Equals("PTC-1", ignoreCase))
{
return "PTB-1";
}
else if (ptc.Equals("PTC-1", ignoreCase))
{
return "PTB-2";
}
else
{
return "PTB-3";
}
}
Currently I have done like:
List<string> keys = rawCollection.Keys.ToList();
foreach (string key in keys)
{
string behavior = GiveBehavior(rawCollection[key]);
rawCollection[key] = behavior;
}
This is how I update the dictionary..
Is there anyway tat can be done via LINQ...
You could try the following:
List<string> keys = rawCollection.Keys.ToList();
keys.ForEach(key => { rawCollection[key] = GiveBehavior(rawCollection[key]); });
That should do it
rawCollection = rawCollection.ToDictionary(item => item.Key, item => GiveBehavior(item.Key));

Resources