So I'm trying to use FindAll to return a list of objects that match. It works great when I only use one condition, for example
patientstatus = statuslist.FindAll(delegate(StatusReader.onestatus p1)
{
return p1.WL_ID == patlist[i].wl_id;
});
But I would like to use multiple conditions, some of which contain if statements and I can't figure out how. It seems like the format needs to have a return statement, and the example from Microsoft (http://msdn.microsoft.com/en-us/library/fh1w7y8z.aspx) only uses one condition.
I could either have multiple FindAll methods for each condition, or just make a loop that scans through all the values myself, but there's got to be an obvious thing I'm missing, right?
I'm not quite sure what "if loops" are, but you can always just stitch them together:
patientstatus = statuslist.FindAll(delegate(StatusReader.onestatus p1)
{
if(p1.WL_ID != patlist[i].wl_id)
return false;
if(otherStuff != 5)
return false;
for(var x in p1.stuff)
if(x == 7)
return false;
return true;
});
Try the following:
var patientStatus = statusList.Where(p => p
{
// Put in logic here as you need
return p.WL_ID == patlist[i].wl_id || p.YourSecondProperty == WhateverYouWantToCheck;
}
You can think about something like
public abstract class Condition
{
public abstract bool Sutisfied(StatusReader.onestatus status);
}
public class Condition1 : Condition
{
public override bool Sutisfied(StatusReader.onestatus status) {
//check for something and return
}
}
public class Condition2 : Condition
{
public override bool Sutisfied(StatusReader.onestatus status) {
//check for something and return
}
}
After can have a list of conditions, like
List<Condition> conditions =
new List<Condition>{new Conditon1(), new Condition2()}
and after this list use inside
patientstatus = statuslist.FindAll(delegate(StatusReader.onestatus status)
{
return conditions.TrueForAll(c=>c.Sutisfied(status));
});
Your delegate simply needs to return true for a match to your conditions and false for a non-match to your conditions. It doesn't have to be a single line return statement. You can create boolean values, have if statements, for loops, and anything else you want in your delegate - so long as it returns true or false along all code paths.
So you can do as many if statements or loops as you want.
If you really want to maintain it as one line, you can do something like the following...
return (condition1 == condition1) || (condition2 == condition2) || (condition3 == condition3);
Related
Assume I have a list of binary parameters (in reality it is a list of checkboxes' IsChecked.Value property). I'm trying to get the bool? (ternary) result that:
is true if all the elements in the list are true
is false if all the elements in the list are false
is null in all other cases, thus there are both true and false elements in the list or the list is empty
Until now I came up with the solution that requires iterating over the list twice (checking whether all elements are either true or false) and then comparing the results to deciding whether to return true, false or null.
This is my code:
bool checkTrue = myListOfBooleans.All(l => l);
bool checkFalse = myListOfBooleans.All(l => !l);
bool? result = (!checkTrue && !checkFalse) ? null : (bool?)checkTrue;
How can I achieve it in only one iteration over the list?
You could do that by using Aggegrate
public bool? AllSameValue(List<bool> myListOfBooleans)
{
if(myListOfBooleans.Count == 0) return null; // or whatever value makes sense
return myListOfBooleans.Cast<bool?>().Aggregate((c, a) => c == a ? a : null);
}
That casts your values to bool? so that you can then compare them and return the value if that they all match or null if there is a difference.
Of course you could exit early by taking the first one and using All to see if the rest match or not.
public bool? AllSameValue(List<bool> myListOfBooleans)
{
if(myListOfBooleans.Count == 0) return null; // or whatever value makes sense
bool first = myListOfBooleans[0];
return myListOfBooleans.All(x => x == first ) ? first : null;
}
You can simply count the true values:
int c = myListOfBooleans.Count(l => l);
bool? result = c == myListOfBooleans.Count
? (bool?)true
: (c == 0 ? (bool?)false : null);
Note that this is true for an empty list, you may want to tweak that according to your required logic.
For a better performance (though I don't think it matters in a UI context) you could write an extension that could even return early if the result is clear (instead of iterating through the whole list):
public static bool? AllOrNothing(this IEnumerable<bool> list)
{
if (list == null) throw new ArgumentNullException(nameof(list));
using(var enumerator = list.GetEnumerator())
{
if (!enumerator.MoveNext())
return null; // or true or false, what you need for an empty list
bool? current = enumerator.Current;
while(enumerator.MoveNext())
if (current != enumerator.Current) return null;
return current;
}
}
And use it:
bool? result = myListOfBooleans.AllOrNothing();
I have some code written in C# for which I need to add some conditions. From one of my methods, I'm calling another method "UpdateData()", which updates some data into the database. Now for this, I need to add some conditions.
There will be appsetting in the config file, which is a boolean value. If the value is true, then the conditions in point2 have to be checked, if the value is false, it has to directly call UpdateData() method.
There are few types and statuses which needs be checked if the point1 is true.
Condition 1: If type is 'A' and status is "Complete" - then call "UpdateData()".
Condition 2 : If type is 'B' and status is "Complete" or "Partial" or "some xyz" - then call "UpdateData()".
So for this I have written the below code :
bool checkStatus = Convert.ToBoolean(ConfigurationManager.AppSettings["CheckStatus"]);
if (checkStatus)
{
if (type == "A" && status == "Complete")
{
UpdateData();
}
else if (type == "B" && (status == "Complete" || status == "Other status" || status == "someother status"))
{
UpdateData(); // for type B , data should not be updated if status is anything other than those in condition.
}
}
else
{
UpdateData();
}
This is working as expected. But I do not want to write nested if-else. If tomorrow there is some other status and type I need to include, I need to add another if condition here.
Is there any better or optimized way of writing it?
I personally think what you have is fine. However, if you really don't like it, you could fiddle with local methods i guess
bool CheckA() => type == "A" && status == "Complete";
bool CheckB() => type == "B" && (status == "Complete" || status == "Other status" || status == "someother status")
if (!checkStatus || CheckA() || CheckB())
UpdateData();
or
bool Check(string val, params string[] list) => type == val && list.Contains(status);
// uglay, yet approachable
if (!checkStatus ||
Check("A", "Complete") ||
Check("B", "Complete", "Other status", "someother status"))
{
UpdateData();
}
Note : I personally wouldn't do these, though it might be your cup of tea
If it is to optimise the ability to add a new one quickly, I would've put it in an array.
bool[] checks = new bool[]{
(type == "A" && status == "Complete"),
(type == "B" && (status == "Complete" || status == "Other status" || status == "someother status"))
}
if (!checkStatus || checks.Contains(false)) //'Contains' requires Linq, it also works with 'checks.Any(c => !c)'
{
UpdateData();
}
This way you only need to add a new condition in the bool array and you don't have to update the if-statement for it. And you can comment out one quickly if you don't need it.
Though, it's usefulness depends on how many conditions you may expect to add.
I guess the main point of this code is to ensure the update runs when the conditions are met, which is done via unit testing.
So, I would look at how I could write this code in a testable manner so I can be sure that it does what it says on the tin.
One way to do it could be something like this:
public bool AppSettingsRunStatusMet(string appSettingsCheckStatus)
{
return Convert.ToBoolean(appSettingsCheckStatus);
}
public bool TypeARunStatusMet(string type, string status)
{
return (type.Equals("A") && status.Equals("Complete"))
}
public bool TypeBRunStatusMet(string type, string status)
{
return (
type.Equals("B") &&
(
status.Equals("Complete") ||
status.Equals("Other status") ||
status.Equals("someother status")
)
}
This is starting to shape up as a rules engine and you can have as many rules as you need
each if statement can now call one method and each rule is separated in its own method which can now be easily tested properly.
You could put all rules in their own class(es), have the engine return a status and if that status is true then run the update. The main idea is to separate config code, from the status analysis and from the code which runs the update and does whatever it is it needs to do.
I'd prefer doing something like this, so that when new cases shows up or validation criteria changes we can just whitelist new case. This is simple/maintainable, works well for growing set of valid_cases with little changes.
using System;
using System.Collections.Generic;
public class Program
{
class Case{
string type;
string status;
public Case(string type_val, string status_val ){
status = status_val;
type = type_val;
}
public override int GetHashCode()
{
return type.GetHashCode()+status.GetHashCode();
}
public override bool Equals(object obj)
{
Case test = obj as Case;
if (test== null)
return false;
return type == test.type && status == test.status ;
}
}
public static void Main()
{
bool checkStatus = true;
HashSet<Case> vaild_cases = new HashSet<Case>();
vaild_cases.Add(new Case("A","Complete"));
vaild_cases.Add(new Case("B","Complete"));
vaild_cases.Add(new Case("B","Other status"));
vaild_cases.Add(new Case("B","someother status"));
Case current_case = new Case("A","Complete");
if (!checkStatus || vaild_cases.Contains(current_case))
UpdateData();
}
static void UpdateData()
{
Console.WriteLine("Hello, World!");
return;
}
}
Cheers !!
Another option is this:
if((new string[] {"Complete", "Other status", "someother status"}.Contains(status) && type == "B") ||
(status == "Complete" && type == "A") ||
!checkStatus)
{
UpdateData();
}
I have the following nested if clause, I was wondering if I, by applying some pattern, can simplify it?
The code checks to see if it needs an authorizationStartDate, and if it does, but does not have it, returns true.
I've considered the Strategy Pattern, the "Replace conditional with polymorphism" method, the Specification Pattern and various others, but I haven't found anything which I liked.
private bool IsMissingAuthorizationStartDate(ApplicationStatusData data)
{
if (data.ApplicationStatus == ApplicationStatusType.ApplicationApproved)
{
if (data.ApplicationPurpose == ApplicationPurpose.New)
{
if (data.ProductStatus?.ProductStatusType == ProductStatusType.ApplicationForNewProductReceived)
{
if (data.ApplicationTypePesticide == ApplicationTypePesticide.Authorisation ||
data.ApplicationTypePesticide == ApplicationTypePesticide.ProvisionalAuthorisation ||
data.ApplicationTypePesticide == ApplicationTypePesticide.MutualRecognition ||
data.ApplicationTypePesticide == ApplicationTypePesticide.Derogation ||
data.ApplicationTypePesticide == ApplicationTypePesticide.DispensationPreviousAssessment ||
data.ApplicationTypePesticide == ApplicationTypePesticide.ResearchAndDevelopmentPurposesExperimentOrTestProgram ||
data.ApplicationTypePesticide == ApplicationTypePesticide.ResearchAndDevelopmentPurposesExperimentOrTestProgramKnownProduct ||
data.ApplicationTypePesticide == ApplicationTypePesticide.ParallelTradePermit ||
data.ApplicationTypePesticide == ApplicationTypePesticide.Copy
)
{
if (!data.AuthorizationStartDate.HasValue)
{
return true;
}
}
}
}
else if (data.ApplicationPurpose == ApplicationPurpose.Renewal)
{
if (data.ProductStatus.ProductStatusType == ProductStatusType.ProductAuthorised)
{
if (data.ApplicationTypePesticide == ApplicationTypePesticide.ReAuthorisation ||
data.ApplicationTypePesticide == ApplicationTypePesticide.ParallelTradePermit ||
data.ApplicationTypePesticide == ApplicationTypePesticide.Copy
)
{
if (!data.AuthorizationStartDate.HasValue)
{
return true;
}
}
}
}
}
// else
return false;
}
The pattern I would use here is just encapsulation. The nesting here is hard to follow, and worsened by the equality comparisons. If possible, instead of exposing the raw field, try encapsulating the intent.
e.g. Instead of if (data.ApplicationPurpose == ApplicationPurpose.Renewal) try extending ApplicationStatusData with a property like
bool IsRenewalApplication
{
get
{
return this.ApplicationPurpose == ApplicationPurpose.Renewal;
}
}
so your code reads cleaner, with more expression: if (data.IsRenewalApplication) { ... }
Particularly where you have that massive if this or that or that or that, put it under a well-named property like IsInterestingPesticide.
If you can't change ApplicationStatusData for some reason, you can do the same thing with member functions that return Boolean values, expressing the same intent.
HTH!
PS, You might even want to encapsulate the entirety of the nested-ifs into a single concept. Then you'd just have 2 Boolean tests before you return false.
I suspect you might want to take a look at the next level up in the code, the fact its returning a boolean indicates this is being used in a conditional by something else.
That said I do usually like the chain of responsibility pattern for this sort of thing. But I personally wouldn't have it return a boolean, I'd have the responsible object perform an action if it was determined to be responsible for that type of data (i.e. Another level up).
Just an option for you to consider, there isn't a hard and fast rule for this kind of thing.
This doesn't really answer to your question which was about design pattern, but that might still interest you.
You could rewrite your method like that.
First two arrays:
private ApplicationTypePesticide[] typePesticidesNewPurpose
= new ApplicationTypePesticide[]
{
ApplicationTypePesticide.Authorisation,
ApplicationTypePesticide.ProvisionalAuthorisation,
ApplicationTypePesticide.MutualRecognition,
ApplicationTypePesticide.Derogation,
ApplicationTypePesticide.DispensationPreviousAssessment,
ApplicationTypePesticide.ResearchAndDevelopmentPurposesExperimentOrTestProgram,
ApplicationTypePesticide.ResearchAndDevelopmentPurposesExperimentOrTestProgramKnownProduct,
ApplicationTypePesticide.ParallelTradePermit,
ApplicationTypePesticide.Copy
};
private ApplicationTypePesticide[] typePesticidesRenewalPurpose
= new ApplicationTypePesticide[]
{
ApplicationTypePesticide.ReAuthorisation,
ApplicationTypePesticide.ParallelTradePermit,
ApplicationTypePesticide.Copy
};
Then your previous method becomes:
private bool IsMissingAuthorizationStartDate(ApplicationStatusData data)
{
return data.ApplicationStatus == ApplicationStatusType.ApplicationApproved
&& (IsMissingAuthorizationStartDatePart2(data, ApplicationPurpose.New,
ProductStatusType.ApplicationForNewProductReceived, typePesticidesNewPurpose)
|| IsMissingAuthorizationStartDatePart2(data, ApplicationPurpose.Renewal,
ProductStatusType.ProductAuthorised, typePesticidesRenewalPurpose));
}
private bool IsMissingAuthorizationStartDatePart2(ApplicationStatusData data,
ApplicationPurpose purpose, ProductStatusType statusType,
params ApplicationTypePesticide[] typePesticides)
{
return (data.ApplicationPurpose == purpose
&& data.ProductStatus.ProductStatusType == statusType
&& statusType.Any(st => data.ApplicationTypePesticide == st)
&& !data.AuthorizationStartDate.HasValue);
}
Note: you can remove the params keyword if you always call the method like in this example.
You should also think about rename the part2 method.
I'm a little bit confused by the explanations of linq online so I figured I'd make a thread.
I want to replace my foreach statements with linq statements as I'm sure doing little things like this will make me program better.
Example of what I'd like to use LINQ with:
public bool CheckForAccount(int accountID)
{
bool status = false;
foreach (AccountHolders accountHolder in AccountHoldersList)
{
if (accountHolder.AccountNumber == accountID)
{
status = true;
break;
}
}
return status;
}
Please can you provide an explanation of how it works too so I understand what you're doing.
Thanks in advance!
So probably the most succinct statement would be:
public bool CheckForAccount(int accountId)
{
return this.AccountHolderList.Any(x => x.AccountNumber == accountId);
}
In English this says
Check AccountHolderList for any cases where the AccountNumber property is equal to accountId. If there are any, return true, otherwise return false.
both
AccountHolderList.Any(x => x.AccountNumber == accountId);
and
AccountHoldersList.Exists(p => p.AccountNumber == accountId);
work equally well. Here is a more in-depth explanation of the differences:
Linq .Any VS .Exists - Whats the difference?
You could also use this:
var match = AccountHolderList.FirstOrDefault(x => x.AccountNumber == accountId);
return match != null ? true : false;
if you want to get a reference to the match as well. This works assuming accountId is unique
This is my setup
class EditorTabViewModel : TabViewModel {
...
public bool CanSave { get; set; };
}
ObservableCollection<TabViewModel> _tabs
I want to check if there are any tabs in _tabs that are EditorTabViewModel that has property CanSave set to true
i did something like ...
var tabs = from t in _tabs
where t is EditorTabViewModel
&& ((EditorTabViewModel)t).CanSave == true
select t;
if (tabs.Count() > 0)
return true;
else
return false;
I wonder if there is a better way to do this? maybe i won't need to retrieve all tabs, or maybe I just need to query the count or something?
How about:
return _tabs.OfType<EditorTabViewModel>().Any(t => t.CanSave);
Here:
OfType<> is a non-buffering filter that restricts us to EditorTabViewModel
Any is short-circuiting, so returns true as soon as a match is found
Yes, you can improve. Something like this would probably work:
return _tabs.Any(x => x is EditorTabViewModel && ((EditorTabViewModel)x).CanSave);
Using the linq extensions you could write something like
_tabs.Any( p => p is EditorTabViewModel && ((EditorTabViewModel)t).CanSave)
Try something like:
return _tabs.FirstOrDefault(y => y is EditorTabViewModel && ((EditorViewModel)t).CanSave) != null;