I made a pattern which i dont really like.
It is as the following:
List<Element> listOfPossibleResults = getAllPossibleResults();
Element result = findResult(getFirstPriorityElements(listOfPossibleResults));
if (result!= null)
{
return result;
}
result = findResult(getSecondPriorityElements(listOfPossibleResults));
if (result!= null)
{
return result;
}
private Element findResult(List<Element> elements) {...};
private List<Element> getFirstPriorityElements(List<Element> elements) {...};
private List<Element> getSecondPriorityElements(List<Element> elements) {...};
etc..
Basically i'am creating sublists based on a couple of rules. After creating the sublist, i try and find a specific element in it. If i dont find, i move on to the next priority, and so on.
I would like a solution where i can iterate over these criterias, until i find a solution. But i dont know how to get them to a format which i can iterate over.
Can you guys give me a C# specific solution of the issue?
As #Lepijohnny mentioned, you can use Chain of responsibility design pattern. For example:
abstract class Handler<TRequest, TResult>
{
protected Handler<TRequest, TResult> successor;
public void SetSuccessor(Handler<TRequest, TResult> successor)
{
this.successor = successor;
}
public abstract TResult HandleRequest(TRequest request);
}
class FirstHandler : Handler<List<Element>, Element>
{
public override void HandleRequest(TRequest request)
{
Element result = findResult(getFirstPriorityElements(request));
if (result == null)
{
result = sucessor?.HandleRequest(request);
}
return result;
}
private Element findResult(List<Element> elements) {...};
private List<Element> getFirstPriorityElements(List<Element> elements) {...};
}
class SecondHandler : Handler<List<Element>, Element>
{
public override void HandleRequest(TRequest request)
{
Element result = findResult(getSecondPriorityElements(request));
if (result == null)
{
result = sucessor?.HandleRequest(request);
}
return result;
}
private Element findResult(List<Element> elements) {...};
private List<Element> getSecondPriorityElements(List<Element> elements) {...};
}
Usage:
void Example()
{
// Setup Chain of Responsibility
var h1 = new FirstHandler();
var h2 = new SecondHandler();
h1.SetSuccessor(h2);
var result = h1.Handle(new List<Element>());
}
It's a just quick example. I think it describe how this pattern works and you will be able to adjust it for your needs.
In the "result" class put a property called "Priority (int)" then:
result = listOfPossibleResults.GroupBy(x => x.Priority).OrderBy(x => x.Key);
then:
return result.FirstOrDefault(x => x.Count() > 0);
You will need to fill in the priority of the result items when you first retrieve them.
P.S. I typed the code right here, forgive me if there is a spelling mistake somewhere.
If you could refactor the methods getFirstPriorityElements(List<> list) to a single getPriorityElements(List<> list, int nr) you could do the following
method IteratePredicates(List<> list, int nr = 0)
{
if (nr>maxpriority) return null;
return findresult(getPriorityElements(list,nr)) ?? IteratePredicates(list,nr++);
}
In a for loop:
method IteratePredicates(List<> list, int nr = 0)
{
for (int i = 0; i < maxpriority; i++)
{
var result = findresult(getPriorityElements(list, nr));
if (result != null)
return result;
}
return null;
}
Am I right that your get__PriorityElements is literally a filter? In that case, it's more declarative and hopefully more readable to treat those like this:
Func<Element, bool> isFirstPriority = ...;
var firstPriorityElements = elements.Where(isFirstPriority);
And now your overall goal is to extract a single element (or none) from the highest-possible priority subsequence, using a predicate contained in findResult? So replace this with an actual predicate
Func<Element, bool> isResult = ...;
like so. Now you want to look through all the first priority elements for an isResult match, then if not found all the second priority elements, etc. This sounds just like a sequence concatenation! So we end up with
var prioritisedSequence = elements
.Where(isFirstPriority)
.Concat(elements
.Where(isSecondPriority))
.Concat....;
And finally the result
var result = prioritisedSequence
.FirstOrDefault(isResult);
Since Where and Concat are lazily enumerated this has the benefit that it is declarative while avoiding more work than necessary, and it's lightweight and 'LINQy' as well.
If you want abstract it even more, and anticipate changes in how priorities will be arranged, you could actually make a higher order list for those like this:
IEnumerable<Func<Element, bool>> priorityFilters = new[]
{
isFirstPriority,
isSecondPriority,
...
};
and then the concatenation can be performed as an aggregation over that sequence:
var prioritisedSequence = priorityFilters
.Aggregate(
Enumerable.Empty<Element>(),
(current, filter) => current.Concat(elements.Where(filter)));
This change may make it easier to add new priorities in future, or you may think it clutters and hides the intention of your code.
You can treat methods as objects using Func<T, T>, and then you can also put them in e.g. an array. Then you can iterate over the array, calling the methods one by one until a result is found.
The solution then becomes:
var methods = new Func<List<Element>, List<Element>>[]
{ getFirstPriorityElements, getSecondPriorityElements };
return methods
.Select(method => findResult(method(listOfPossibleResults)))
.Where(result => result != null)
.FirstOrDefault();
This is short and readable, works without changing your methods or types, and no need to add classes just for the sake of applying a pattern.
You can use the specs pattern Here is a sample code:
Create a interface with a criteria:
public interface ISpecification<T>
{
Expression<Func<T, bool>> Criteria { get; }
}
Then create a class that holds your query specs:
public class GlobalSongSpecification : ISpecification<Song>
{
public List<int> GenreIdsToInclude { get; set; } = new List<int>();
public List<int> AlbumIdsToInclude { get; set; } = new List<int>();
public List<string> ArtistsToInclude { get; set; } = new List<string>();
public string TitleFilter { get; set; }
public int MinRating { get; set; }
[JsonIgnore]
public Expression<Func<Song, bool>> Criteria
{
get
{
return s =>
(!GenreIdsToInclude.Any() || s.Genres.Any(g => GenreIdsToInclude.Any(gId => gId == g.Id))) &&
(!AlbumIdsToInclude.Any() || AlbumIdsToInclude.Contains(s.AlbumId)) &&
(!ArtistsToInclude.Any() ||ArtistsToInclude.Contains(s.Artist)) &&
(String.IsNullOrEmpty(this.TitleFilter) || s.Title.Contains(TitleFilter)) &&
s.Rating >= MinRating;
}
}
}
Create a repository with a method that exposes one that receives ISpecification:
public interface ISongRepository
{
IEnumerable<Song> List(ISpecification<Song> specification);
//IQueryable<Song> List();
Song GetById(int id);
void Add(Song song);
IEnumerable<string> AllArtists();
IEnumerable<Genre> AllGenres();
}
And your client code call the GlobalSongSpecification, populates it and pass it to the repository in order to filter by the criteria:
public ActionResult Index(List<int> selectedGenres = null,
List<string> selectedArtists = null,
string titleSearch = null,
int minRating = 0,
string filter = null,
string save = null,
string playlistName = null)
{
if (selectedArtists == null) { selectedArtists = new List<string>(); }
if (selectedGenres == null) { selectedGenres = new List<int>(); }
var spec = new GlobalSongSpecification();
spec.ArtistsToInclude.AddRange(selectedArtists);
spec.GenreIdsToInclude.AddRange(selectedGenres);
spec.MinRating = minRating;
spec.TitleFilter = titleSearch;
var songs = _songRepository.List(spec);
//You can work with the filtered data at this point
}
And you populate a razor view or expose it as web api.
The sample code is from pluralsight desing patterns library course Here(Specification Pattern module)
Related
I want to filter an IEnumerable object by a specific property of whatever object it is collecting. I want the option to filter by one or more property value but how many values (and what values) to filter by is only known at runtime.
Ok, so to give an example, the collected objects could be the following struct:
public struct Person
{
public string Name { get; set; }
public string Profession{ get; set; }
}
This struct could then be used by the following list, which I have populated with some arbitrary values:
List<Person> people= new List<Person>;
people.Add(new Person(){Name = "Mickey", Profession="Tinker"};
people.Add(new Person(){Name = "Donald", Profession="Tailor"};
people.Add(new Person(){Name = "Goofy", Profession="Soldier"};
people.Add(new Person(){Name = "Pluto", Profession="Spy"};
This is then put into an IEnumerable (all of them are transferred to it first)
var wantedPeople = from n in this.people select n;
So say a user was only interested in the "Tailor" and "Spy" professions, and via some sort of gui trickery the following collection was created:
List<string> wantedProfessions = new List<string>();
wantedProfessions.Add("Tailor");
wantedProfessions.Add("Spy");
Now what Linq statement can I use to filer my wantedPeople so it only includes the tailor and spy entries?
I know I could use a where clause but I don't know how to tailor it to get what I want (and doing the following is not what I want as it only works with the wantedProfessions collection above (e.g. this collection will change at runtime):
wantedPeople = from n in wantedPeople
where n.Profession == wantedProffessions[0] || n.Profession == wantedProffessions[1]
select n;
If you want to check any wanted profession from given list:
wantedPeople = from n in wantedPeople
where wantedProffessions.Contains(n.Profession)
select n;
Or you can build query with lambda syntax by applying filters one by one:
var query = people.AsEnumerable();
if (!String.IsNullOrEmpty(name))
query = query.Where(p => p.Name == name);
if (wantedProfessions.Any())
query = query.Where(p => wantedProfessions.Contains(p.Profession));
If you wanted to create more complex filters, like some name, and several professions, you can use Specification pattern. Specification can be defined by this simple interface:
public interface ISpecification<T>
{
bool Satisfied(T entity);
}
It just checks whether given entity (person) satisfies specification. Specification also look very simple:
public class PersonNameSpecification : ISpecification<Person>
{
private string _name;
public PersonNameSpecification(string name)
{
_name = name;
}
public bool Satisfied(Person person)
{
return person.Name == _name;
}
}
Profession specification:
public class PersonProfessionSpecification : ISpecification<Person>
{
private string[] _professions;
public PersonProfessionSpecification(params string[] professions)
{
_professions = professions;
}
public bool Satisfied(Person person)
{
return _professions.Contains(person.Profession);
}
}
You can create specifications which implement boolean logic, like OrSpecification or AndSpecification:
public class AndSpecification<T> : ISpecification<T>
{
private ISpecification<T> _specA;
private ISpecification<T> _specB;
public AndSpecification(ISpecification<T> specA, ISpecification<T> specB)
{
_specA = specA;
_specB = specB;
}
public bool Satisfied(T entity)
{
return _specA.Satisfied(entity) && _specB.Satisfied(entity);
}
}
public static class SpecificationExtensions
{
public static ISpecification<T> And<T>(
this ISpecification<T> specA, ISpecification<T> specB)
{
return new AndSpecification<T>(specA, specB);
}
}
Now you can create complex specification which describes people you want to get:
var professionSpec = new PersonProfessionSpecification("Tailor", "Spy");
var nameSpec = new PersonNameSpecification("Pluto");
var spec = professionSpec.And(nameSpec);
And get required people:
var result = people.Where(spec.Satisfied);
Sergey B's Solution is the correct one for your example.
Assuming that you weren't using a collection that had the Contains() method, you could also do the following:
var wantedPeople = from n in people
from p in wantedProffessions
where n.Profession.Equals(p)
select n;
I saw a similar question here with a very good solutions:
Simplest way to form a union of two lists
But the problem here is, it works when there is only one parameter in each list (int value). I had this rquirement to combine 5 different lists containing objects of the same class without data redundancy and the final list should be sorted out in ascending order of int value.
Example:
Class Company //data Class
{
int companyNo;
string Name;
}
Class CompanyList : List<Company>
{
.................
public CompanyList GetList(int userID)
{
.....
}
}
Class company has a pulic method returning list of companies corresponding to a search criteria, let us userID.
CompanyList list1 = CompanyList .GetList(userID1);
CompanyList list2 = CompanyList .GetList(userID2);
CompanyList list3 = CompanyList .GetList(userID3);
CompanyList list4 = CompanyList .GetList(userID4);
CompanyList list5 = CompanyList .GetList(userID5);
The solution I implemented is (worked well):
CompanyList _finalList = list1;
*foreach (CompanyList _list in {_list2 ,_list3 ,_list4 ,_list5}) //loop thorugh all other list
{
foreach (Company item in _list)
{
for (int i = 0; i <= _finalList.Count - 1; i++)
{
if (_finalList.Item(i).CompanyNo== item.CompanyNo)
//***EXIT TAKE NEXT LIST - GO TO *
}
if (i == _finalList.Count - 1) //else check end of first list
{
//company no. not yet encountered(new)
int pos = 0;
foreach (Company companyInfo in _finalList) //search for position for new company no.
{
if (companyInfo.CompanyNo> item.CompanyNo)
{
break;
}
else
{
pos = pos + 1; //increment position
}
}
_finalList.Insert(pos, item); 'Add new item
}
}
}
**the code is converted from VB.Net to C#. Here I could not find the quivalent code piece for this line so replaced it with the concept.
I am not an expert C# programmer and just wondering if there is any better or simpler way to do this?
Data example:
Input:
list1[0] = {0,"TCS"};
list1[1] = {1,"Infosys"};
list2[0] = {8,"IBM"};
list3[1] = {1,"Infosys"};
list4[0] = {0,"TCS"};
list5[0] = {9,"Accenture"};
list5[1] = {6,"HCL"};
Output:
finalList[0] = {0,"TCS"};
finalList[1] = {1,"Infosys"};
finalList[2] = {6,"HCL"};
finalList[3] = {8,"IBM"};
finalList[4] = {9,"Accenture"};
Regards
Sj
Okay, so you have a number of sequences of something, in your case "something" would be Company, which doesn't overide object.Equals or object.HashCode.
So, a new extension like this, might prove useful
public static IEnumerable<T> Union(
this IEnumerable<T> source,
IEqualityComparer<T> comparer,
params IEnumerable<T>[] others)
{
if (comparer == null)
{
comparer = EqualityComparer<T>.Default;
}
var result = source.Distinct(comparer);
foreach(var o in source)
{
if (o == null)
{
continue;
}
result = result.Union(o, comparer);
}
return result;
}
To make this, and other functions that take an IEqualityComparer simple to use, you could add this class to your code,
public class EqualityComparerImproved<T> : EqaulityComparer<T>
{
private readonly Func<T, T> equalityComparison;
private readonly Func<T, int> hashGenerator;
private EqualityComparerImproved(
Func<T, T> equalityComparison,
Func<T, int> hashGenerator)
{
this.equalityComparison = equalityComparison;
this.hashGenerator = hashGenerator;
}
public static EqualityComparerImproved<T> Create
Func<T, T> equalityComparison,
Func<T, int> hashGenerator)
{
if (equalityComparison == null)
{
throw new ArgumentNullException("equalityComparison");
}
if (hashGenerator == null)
{
throw new ArgumentNullException("hashGenerator");
}
return new EqualityComparerImproved<T>(
equalityComparison,
hashGenerator);
}
public override bool Equals(T x, T y)
{
return this.equalityComparison(x, y);
}
public override int GetHashCode(T obj)
{
return this.hashGenerator(obj);
}
}
Once these two, admittedly lengthy, bits of code were in place you could do
var output = list1.Union(
EqualityComparerImproved<Company>.Create(
(x, y) => x.companyNo == y.companyNo && x.Name == y.Name,
(obj) =>
{
unchecked // Overflow is fine, just wrap
{
int hash = 17;
hash = hash * 23 + obj.companyNo;
hash = hash * 23 + obj.Name.GetHashCode();
return hash;
}
},
list2,
list3,
list4,
list5);
or if companyNo is a unique key,
var output = list1.Union(
EqualityComparerImproved<Company>.Create(
(x, y) => x.companyNo == y.companyNo,
(obj) => obj.companyNo),
list2,
list3,
list4,
list5);
would suffice.
Similar to Habib's solution, but a bit more concise and complete.
int[] userIDs = new[] { userID1, userID2, userID3, userID4, userID5 };
IEnumerable<Company> distinctCompanies =
from companyList in userIDs.Select(CompanyList.GetList)
from company in companyList
group company by company.companyNo into companiesWithSameNo
select companiesWithSameNo.First();
CompanyList finalList = new CompanyList();
finalList.AddRange(distinctCompanies);
You might have a constructor in CompanyList that directly accepts an IEnumerable<Company>, too, so you could directly pass distinctCompanies there instead.
You can use either GroupBy or Union to remove duplicates... Union makes for a little cleaner linq (I think) but either can work... the downside is that you also need a custom IEqualityComparer in this case since equals on your company objects will return false (since they are different instances)... An alternative is to have your Company class implement IEqualityComparer and just copy the code I have implementing that interface into your Company class.
// Union gives you a unique list if it knows how to compare the objects properly
var companyEqualityComparer = new CompanyEqualityComparer();
foreach (var companyList in new List<List<Company>>(){list2, list3, list4, list5})
{
combinedList = combinedList.Union(companyList, companyEqualityComparer);
}
// Order your output list
var finalList = combinedList.OrderBy(c => c.companyNo).ToList();
Define your CompanyEqualityComparer...
// CompanyEqualityComparer which is needed since your companies are different instances
public class CompanyEqualityComparer : IEqualityComparer<Company>
{
public bool Equals(Company x, Company y)
{
return x.companyNo.Equals(y.companyNo);
}
public int GetHashCode(Company obj)
{
return obj.companyNo.GetHashCode();
}
}
I think you need something like:
List<Company> inputList = //Get your input List
List<Company> outputList = inputList.GroupBy(r => r.companyNo)
.Select(grp => new Company
{
companyNo = grp.Key,
Name = grp.First().Name,
})
.OrderBy(r=> r.companyNo)
.ToList();
I have a List of messages.
Each message has a type.
public enum MessageType
{
Foo = 0,
Bar = 1,
Boo = 2,
Doo = 3
}
The enum names are arbitrary and cannot be changed.
I need to return the list sorted as: Boo, Bar, Foo, Doo
My current solution is to create a tempList, add the values in the order I want, return the new list.
List<Message> tempList = new List<Message>();
tempList.AddRange(messageList.Where(m => m.MessageType == MessageType.Boo));
tempList.AddRange(messageList.Where(m => m.MessageType == MessageType.Bar));
tempList.AddRange(messageList.Where(m => m.MessageType == MessageType.Foo));
tempList.AddRange(messageList.Where(m => m.MessageType == MessageType.Doo));
messageList = tempList;
How can I do this with an IComparer?
An alternative to using IComparer would be to build an ordering dictionary.
var orderMap = new Dictionary<MessageType, int>() {
{ MessageType.Boo, 0 },
{ MessageType.Bar, 1 },
{ MessageType.Foo, 2 },
{ MessageType.Doo, 3 }
};
var orderedList = messageList.OrderBy(m => orderMap[m.MessageType]);
So, let's write our own comparer:
public class MyMessageComparer : IComparer<MessageType> {
protected IList<MessageType> orderedTypes {get; set;}
public MyMessageComparer() {
// you can reorder it's all as you want
orderedTypes = new List<MessageType>() {
MessageType.Boo,
MessageType.Bar,
MessageType.Foo,
MessageType.Doo,
};
}
public int Compare(MessageType x, MessageType y) {
var xIndex = orderedTypes.IndexOf(x);
var yIndex = orderedTypes.IndexOf(y);
return xIndex.CompareTo(yIndex);
}
};
How to use:
messages.OrderBy(m => m.MessageType, new MyMessageComparer())
There is a easier way: just create ordereTypes list and use another overload of OrderBy:
var orderedTypes = new List<MessageType>() {
MessageType.Boo,
MessageType.Bar,
MessageType.Foo,
MessageType.Doo,
};
messages.OrderBy(m => orderedTypes.IndexOf(m.MessageType)).ToList();
Hm.. Let's try to take advantages from writing our own IComparer. Idea: write it like our last example but in some other semantic. Like this:
messages.OrderBy(
m => m.MessageType,
new EnumComparer<MessageType>() {
MessageType.Boo,
MessageType.Foo }
);
Or this:
messages.OrderBy(m => m.MessageType, EnumComparer<MessageType>());
Okay, so what we need. Our own comparer:
Must accept enum as generic type (how to solve)
Must be usable with collection initializer syntax (how to)
Must sort by default order, when we have no enum values in our comparer (or some enum values aren't in our comparer)
So, here is the code:
public class EnumComparer<TEnum>: IComparer<TEnum>, IEnumerable<TEnum> where TEnum: struct, IConvertible {
protected static IList<TEnum> TypicalValues { get; set; }
protected IList<TEnum> _reorderedValues;
protected IList<TEnum> ReorderedValues {
get { return _reorderedValues.Any() ? _reorderedValues : TypicalValues; }
set { _reorderedValues = value; }
}
static EnumComparer() {
if (!typeof(TEnum).IsEnum)
{
throw new ArgumentException("T must be an enumerated type");
}
TypicalValues = new List<TEnum>();
foreach (TEnum value in Enum.GetValues(typeof(TEnum))) {
TypicalValues.Add(value);
};
}
public EnumComparer(IList<TEnum> reorderedValues = null) {
if (_reorderedValues == null ) {
_reorderedValues = new List<TEnum>();
return;
}
_reorderedValues = reorderedValues;
}
public void Add(TEnum value) {
if (_reorderedValues.Contains(value))
return;
_reorderedValues.Add(value);
}
public int Compare(TEnum x, TEnum y) {
var xIndex = ReorderedValues.IndexOf(x);
var yIndex = ReorderedValues.IndexOf(y);
// no such enums in our order list:
// so this enum values must be in the end
// and must be ordered between themselves by default
if (xIndex == -1) {
if (yIndex == -1) {
xIndex = TypicalValues.IndexOf(x);
yIndex = TypicalValues.IndexOf(y);
return xIndex.CompareTo(yIndex);
}
return -1;
}
if (yIndex == -1) {
return -1; //
}
return xIndex.CompareTo(yIndex);
}
public void Clear() {
_reorderedValues = new List<TEnum>();
}
private IEnumerable<TEnum> GetEnumerable() {
return Enumerable.Concat(
ReorderedValues,
TypicalValues.Where(v => !ReorderedValues.Contains(v))
);
}
public IEnumerator<TEnum> GetEnumerator() {
return GetEnumerable().GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() {
return GetEnumerable().GetEnumerator();
}
}
So, well, let's make sorting more faster. We need to override default OrderBy method for our enums:
public static class LinqEnumExtensions
{
public static IEnumerable<TSource> OrderBy<TSource, TEnum>(this IEnumerable<TSource> source, Func<TSource, TEnum> selector, EnumComparer<TEnum> enumComparer) where TEnum : struct, IConvertible
{
foreach (var enumValue in enumComparer)
{
foreach (var sourceElement in source.Where(item => selector(item).Equals(enumValue)))
{
yield return sourceElement;
}
}
}
}
Yeah, that's lazy. You can google how yield works. Well, let's test speed. Simple benchmark: http://pastebin.com/P8qaU20Y. Result for n = 1000000;
Enumerable orderBy, elementAt: 00:00:04.5485845
Own orderBy, elementAt: 00:00:00.0040010
Enumerable orderBy, full sort: 00:00:04.6685977
Own orderBy, full sort: 00:00:00.4540575
We see, that our own orderBy by is more lazy that standart order by (yeah, it doesn't need to sort everything). And faster even for fullsort.
Problems in this code: it doesn't support ThenBy(). If you need this, you can write your own linq extension that returns IOrderedEnumerable There are a blog post series by Jon Skeet which goes into LINQ to Objects in some depth, providing a complete alternative implementation. The basis of IOrderedEnumerable is covered in part 26a and 26b, with more details and optimization in 26c and 26d.
Instead of using an IComparer, you could also use a SelectMany approach, which should have better performance for large message lists, if you have a fixed number of message types.
var messageTypeOrder = new [] {
MessageType.Boo,
MessageType.Bar,
MessageType.Foo,
MessageType.Doo,
};
List<Message> tempList = messageTypeOrder
.SelectMany(type => messageList.Where(m => m.MessageType == type))
.ToList();
You may avoid writing a completely new type just to implement IComparable. Use the Comparer class instead:
IComparer<Message> comparer = Comparer.Create<Message>((message) =>
{
// lambda that compares things
});
tempList.Sort(comparer);
You can build a mapping dictionary dynamically from the Enum values with LINQ like this:
var mappingDIctionary = new List<string>((string[])Enum.GetNames(typeof(Hexside)))
.OrderBy(label => label )
.Select((i,n) => new {Index=i, Label=n}).ToList();
Now any new values added to the Enum n future will automatically get properly mapped.
Also, if someone decides to renumber, refactor, or reorder the enumeration, everything is handled automatically.
Update:
As pointed out below, Alphabetical ordering was not called for; rather a semi- alphabetical ordering, so essentially random. Although not an answer to this particular question, this technique might be useful to future visitors, so I will leave it standing.
No need to have the mapping. This should give you the list and order based on the enum. You don't have to modify anything even when you change the enum's order or and new items...
var result = (from x in tempList
join y in Enum.GetValues(typeof(MessageType)).Cast<MessageType>()
on x equals y
orderby y
select y).ToList();
If you are about to get this working with Entity Framework (EF), you would have to spread out your enum in your OrderBy as such:
messageList.OrderBy(m =>
m.MessageType == MessageType.Boo ? 0 :
m.MessageType == MessageType.Bar ? 1 :
m.MessageType == MessageType.Foo ? 2 :
m.MessageType == MessageType.Doo ? 3 : 4
);
This creates a sub select with CASE WHEN, then ORDER BY on that temporary column.
My first (and really horrible post) is below.
I try to do a complete example what I want to get. I hope this will be left explained a bit better.
using System;
using System.Collections.Generic;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List<Boy> boys = new List<Boy>();
boys.Add(new Boy("Jhon", 7));
boys.Add(new Boy("Oscar", 6));
boys.Add(new Boy("Oscar", 7));
boys.Add(new Boy("Peter", 5));
ClassRoom myClass = new ClassRoom(boys);
Console.WriteLine(myClass.ByName("Oscar").Count); // Prints 2
Console.WriteLine(myClass.ByYearsOld(7).Count); // Prints 2
// This has errors...................
// But this is as I would like to call my BySomeConditions method....
Console.WriteLine( // It should print 1
myClass.BySomeConditions([myClass.ByName("Oscar"),
myClass.ByYearsOld(7)]
)
);
Console.ReadKey();
}
class ClassRoom
{
private List<Boy> students;
public ClassRoom(List<Boy> students)
{
this.students = students;
}
public List<Boy> ByName(string name)
{
return students.FindAll(x => x.Name == name);
}
public List<Boy> ByYearsOld(int yearsOld)
{
return students.FindAll(x => x.YearsOld == yearsOld);
}
// This has ERRORS.......................
public List<Boy> BySomeConditions(params Func<X, List<Boy>>[] conditions)
{
IEnumerable<Boy> result = students;
foreach (var condition in conditions) {
// I want it ONLY be called with existent functions (ByName and/or ByYearsOld)
result = result.Intersect(condition(this));
}
}
}
class Boy
{
public string Name { get; set; }
public int YearsOld { get; set; }
public Boy(string name, int yearsOld)
{
Name = name;
YearsOld = yearsOld;
}
}
}
}
============== first post =====================
Hello,
I have a class with methods:
public class X
{
private readonly List<string> myList;
public X(List<string> paramList) // string is really an object
{
myList = paramList;
}
// Now I want this...
public List<string> CheckConditions(params Func<T, List<string>>[] conditions)
{
var result = myList;
foreach (Func<T, List<string>> condition in conditions)
{
result = result.Intersect(condition(T));
}
}
public List<string> check1(string S)
{
return myList.FindAll(x => x.FieldS == S);
}
public List<string> check1(int I)
{
return myList.FindAll(x => x.FieldI == I);
}
}
Sorry if there is some error, I have written from scrach to avoid complex real case.
What I want is call my methods like this:
X.check1("Jhon");
or
X.check2(12);
or (this is the goal of my question):
X.CheckConditions(X.check1("Jhon"), X.chek2(12));
Thanks and sorry by my poor example...
It is unclear where your T comes from.
Does this meet your requirements?
public class X<T>
{
private List<T> myList;
public List<T> CheckConditions(params Func<T, bool>[] conditions)
{
IEnumerable<T> query = myList;
foreach (Func<T, bool> condition in conditions)
{
query = query.Where(condition);
}
return query.ToList();
}
}
Then later:
List<T> result = X.CheckConditions(
z => z.FieldS == "Jhon",
z => z.FieldI == 12
);
You need to change the method signature of CheckConditions, it's accepting a variable number of List<string>, not functions.
public List<string> CheckConditions(params List<string>[] lists)
The return type of check1 is List<string>, so that needs to be the type of the parameter that CheckConditions accepts.
There's no reason to make it generic, you know that you want to operate on the current instance of X (so pass in this, instead of the T type parameter). You need to cleanup a few things to to get it to compile (return result and make the type of result and the Intersect call compatible). You can define it like this:
public List<string> CheckConditions(params Func<X, List<string>>[] conditions)
{
IEnumerable<string> result = myList;
foreach (var condition in conditions)
{
result = result.Intersect(condition(this));
}
return result.ToList();
}
Ant then call it like this:
xInstance.CheckConditions(x => x.check1("JHon"), x => x.check1(12));
All that said, I'm not sure why you wouldn't just pass around the results of these functions, instead of passing the actual functions around:
public List<string> CheckConditions(params List<string>[] conditions)
{
IEnumerable<string> result = myList;
foreach (var condition in conditions)
{
result = result.Intersect(condition);
}
return result.ToList();
}
Then call it as in your example, rather than passing in lambda expressions.
you could rewrite you function to look like this:
// Now I want this...
public List<string> CheckConditions(params Func<T, List<string>>[] conditions)
{
var result = myList;
foreach (Func<T, List<string>> condition in conditions)
{
result = result.Intersect(condition(T));
}
}
your call would then be X.CheckConditions(()=>X.check1("Jhon"), ()=>X.chek2(12));
and you need to provide an instance for x (since the methods are instance methods and not static methods)
In your example you pass T as an argument to the functor but T is a type argument som it can't be passed as an argument to the method. Did you mean to pass a value?
This begs for a clarification of why you would want to do this. Maybe if you provided details on what you are trying to accomplish (as opposed to how) then you could get a better solution to your problem.
What you pass to your
X.CheckConditions
is not a reference to the functions, but the returned value of their invocation.
Now, if you pass function reference - it does not come with parameters, unless you construct and pass a data-structure that will contain the function reference and the arguments it should work on.
In this case - generics is not the solution. You should consider another pattern to follow, like command pattern or strategy pattern, where you pass to your CheckConstruction instances of checker-objects, each is instantiated with the parameters it should work on, and either implements or is provided by the validation function.
In the ContainsIngredients method in the following code, is it possible to cache the p.Ingredients value instead of explicitly referencing it several times? This is a fairly trivial example that I just cooked up for illustrative purposes, but the code I'm working on references values deep inside p eg. p.InnerObject.ExpensiveMethod().Value
edit:
I'm using the PredicateBuilder from http://www.albahari.com/nutshell/predicatebuilder.html
public class IngredientBag
{
private readonly Dictionary<string, string> _ingredients = new Dictionary<string, string>();
public void Add(string type, string name)
{
_ingredients.Add(type, name);
}
public string Get(string type)
{
return _ingredients[type];
}
public bool Contains(string type)
{
return _ingredients.ContainsKey(type);
}
}
public class Potion
{
public IngredientBag Ingredients { get; private set;}
public string Name {get; private set;}
public Potion(string name) : this(name, null)
{
}
public Potion(string name, IngredientBag ingredients)
{
Name = name;
Ingredients = ingredients;
}
public static Expression<Func<Potion, bool>>
ContainsIngredients(string ingredientType, params string[] ingredients)
{
var predicate = PredicateBuilder.False<Potion>();
// Here, I'm accessing p.Ingredients several times in one
// expression. Is there any way to cache this value and
// reference the cached value in the expression?
foreach (var ingredient in ingredients)
{
var temp = ingredient;
predicate = predicate.Or (
p => p.Ingredients != null &&
p.Ingredients.Contains(ingredientType) &&
p.Ingredients.Get(ingredientType).Contains(temp));
}
return predicate;
}
}
[STAThread]
static void Main()
{
var potions = new List<Potion>
{
new Potion("Invisibility", new IngredientBag()),
new Potion("Bonus"),
new Potion("Speed", new IngredientBag()),
new Potion("Strength", new IngredientBag()),
new Potion("Dummy Potion")
};
potions[0].Ingredients.Add("solid", "Eye of Newt");
potions[0].Ingredients.Add("liquid", "Gall of Peacock");
potions[0].Ingredients.Add("gas", "Breath of Spider");
potions[2].Ingredients.Add("solid", "Hair of Toad");
potions[2].Ingredients.Add("gas", "Peacock's anguish");
potions[3].Ingredients.Add("liquid", "Peacock Sweat");
potions[3].Ingredients.Add("gas", "Newt's aura");
var predicate = Potion.ContainsIngredients("solid", "Newt", "Toad")
.Or(Potion.ContainsIngredients("gas", "Spider", "Scorpion"));
foreach (var result in
from p in potions
where(predicate).Compile()(p)
select p)
{
Console.WriteLine(result.Name);
}
}
Have you considered Memoization?
The basic idea is this; if you have an expensive function call, there is a function which will calculate the expensive value on first call, but return a cached version thereafter. The function looks like this;
static Func<T> Remember<T>(Func<T> GetExpensiveValue)
{
bool isCached= false;
T cachedResult = default(T);
return () =>
{
if (!isCached)
{
cachedResult = GetExpensiveValue();
isCached = true;
}
return cachedResult;
};
}
This means you can write this;
// here's something that takes ages to calculate
Func<string> MyExpensiveMethod = () =>
{
System.Threading.Thread.Sleep(5000);
return "that took ages!";
};
// and heres a function call that only calculates it the once.
Func<string> CachedMethod = Remember(() => MyExpensiveMethod());
// only the first line takes five seconds;
// the second and third calls are instant.
Console.WriteLine(CachedMethod());
Console.WriteLine(CachedMethod());
Console.WriteLine(CachedMethod());
As a general strategy, it might help.
Can't you simply write your boolean expression in a separate static function which you call from your lambda - passing p.Ingredients as a parameter...
private static bool IsIngredientPresent(IngredientBag i, string ingredientType, string ingredient)
{
return i != null && i.Contains(ingredientType) && i.Get(ingredientType).Contains(ingredient);
}
public static Expression<Func<Potion, bool>>
ContainsIngredients(string ingredientType, params string[] ingredients)
{
var predicate = PredicateBuilder.False<Potion>();
// Here, I'm accessing p.Ingredients several times in one
// expression. Is there any way to cache this value and
// reference the cached value in the expression?
foreach (var ingredient in ingredients)
{
var temp = ingredient;
predicate = predicate.Or(
p => IsIngredientPresent(p.Ingredients, ingredientType, temp));
}
return predicate;
}
Well, in this case, if you can't use Memoization, you're rather restricted since you can really only use the stack as your cache: You've got no way to declare a new variable at the scope you'll need. All I can think of (and I'm not claiming it will be pretty) that will do what you want but retain the composability you need would be something like...
private static bool TestWith<T>(T cached, Func<T, bool> predicate)
{
return predicate(cached);
}
public static Expression<Func<Potion, bool>>
ContainsIngredients(string ingredientType, params string[] ingredients)
{
var predicate = PredicateBuilder.False<Potion>();
// Here, I'm accessing p.Ingredients several times in one
// expression. Is there any way to cache this value and
// reference the cached value in the expression?
foreach (var ingredient in ingredients)
{
var temp = ingredient;
predicate = predicate.Or (
p => TestWith(p.Ingredients,
i => i != null &&
i.Contains(ingredientType) &&
i.Get(ingredientType).Contains(temp));
}
return predicate;
}
You could combine together the results from multiple TestWith calls into a more complex boolean expression where required - caching the appropriate expensive value with each call - or you can nest them within the lambdas passed as the second parameter to deal with your complex deep hierarchies.
It would be quite hard to read code though and since you might be introducing a bunch more stack transitions with all the TestWith calls, whether it improves performance would depend on just how expensive your ExpensiveCall() was.
As a note, there won't be any inlining in the original example as suggested by another answer since the expression compiler doesn't do that level of optimisation as far as I know.
I would say no in this case. I assume that the compiler can figure out that it uses the p.Ingredients variable 3 times and will keep the variable closeby on the stack or the registers or whatever it uses.
Turbulent Intellect has the exactly right answer.
I just want to advise that you can strip some of the nulls and exceptions out of the types you are using to make it friendlier to use them.
public class IngredientBag
{
private Dictionary<string, string> _ingredients =
new Dictionary<string, string>();
public void Add(string type, string name)
{
_ingredients[type] = name;
}
public string Get(string type)
{
return _ingredients.ContainsKey(type) ? _ingredients[type] : null;
}
public bool Has(string type, string name)
{
return name == null ? false : this.Get(type) == name;
}
}
public Potion(string name) : this(name, new IngredientBag()) { }
Then, if you have the query parameters in this structure...
Dictionary<string, List<string>> ingredients;
You can write the query like this.
from p in Potions
where ingredients.Any(i => i.Value.Any(v => p.IngredientBag.Has(i.Key, v))
select p;
PS, why readonly?