Use of Contains with one Except in LINQ - c#

I am trying to get a list of Menus which does not contain "license".
var menus= MenuRepo.GetAll().Where(x => x.Name.Contains("license") == false)
But now i want to exclude one of them, ie., "licenseUser"
I need "licenseUser" in the list.
How can i achieve this?

var menus = MenuRepo.GetAll().Where
(
x => !x.Name.Contains("license") || x.Name == "licenseUser"
);
(note that a == false when a is boolean is the same as !a, and it's shorter to write)

Just add an OR condition which checks whether the menu name is equal to "licenseUser":
var menus = MenuRepo.GetAll().Where(menu => !menu.Name.Contains("license") || menu.Name == "licenseUser");

Related

Remove list items where property = myValue

I've got a problem. I have a list of objects (vehicle).
List<Vehicle> vehicleList = Vehicle.GetVehiclesFromDatabase();
And now I want something like this:
vehicleList.Remove(where vehicleList.Brand == "Volkswagen");
I hope I could explain what my problem is.
Many thanks in advance!
You can use List<T>.RemoveAll:
int recordsRemoved = vehicleList.RemoveAll(v => v.Brand == "Volkswagen");
The method takes a Predicate<T> (= Func<T,bool>), which will remove all items for which the predicate returns true.
For you this is equal to the following method:
bool Filter(Vehicle vehicle)
{
return vehicle.Brand == "Volkswagen";
}
You can use linq to do this, like so
vehicleList = vehicleList.Where(v => v.Brand != "Volkswagen").ToList();
You can also do this with a RemoveAll
vehicleList.RemoveAll(v => v.Brand == "Volkswagen");
You can do like this
var itemToRemove = vehicleList.Single(r => r.Brand == "Volkswagen");
resultList.Remove(itemToRemove);
When you are not sure the item really exists you can use SingleOrDefault. SingleOrDefault will return null if there is no item (Single will throw an exception when it can't find the item). Both will throw when there is a duplicate value (two items with the same id).
var itemToRemove = vehicleList.SingleOrDefault(r => r.Brand == "Volkswagen");
if (itemToRemove != null)
resultList.Remove(itemToRemove);

Return a value or null using LINQ in one line?

I have statements like this all over the place. Is there some way to do it all in one line ? Maybe something in C# 6.0 would help ? I just want to get the value if there is something there and if not then return a empty string or maybe NULL.
var item = ll.Fields.Where(x => x.FieldTitle == "Loan Amount");
if (item.Count() != 0) {
LatestItem.VelocifyLoanAmount = double.Parse(item.FirstOrDefault().Value);
}
EDIT 1: It is a double though other times I need to get a string. I love how quickly I get help for my LINQ questions. My Excel VSTO addin questions get crickets :)
Why not simply:
var item = ll.Fields
.Where(x => x.FieldTitle == "Loan Amount")
.Select(x => (double?)double.Parse(x.Value))
.FirstOrDefault();
One thing you can do is the following:
var item = ll.Fields.FirstOrDefault(x => x.FieldTitle == "Loan Amount")?.Value;
if (!double.TryParse(item, out LatestItem.VelocifyLoanAmount)
{
// do your error case here
}
UPDATE: added C#6.0 syntax to shorten the syntax, and using the preferred TryParse instead for error checking.
UPDATE 2: if for some reason double.Parse is preferred (for instance if a wrapper is handling exceptions for a large piece of code), here is a shorter example.
LatestItem.VelocifyLoanAmount =
double.Parse(ll.Fields.FirstOrDefault(x => x.FieldTitle == "Loan Amount")?.Value);
You can use Select to project the objects in the collection to double? and return FirstOrDefault
double? parsedFirstValueOrNull = ll.Fields
.Where(x => x.FieldTitle == "Loan Amount")
.Select(i => (double?)double.Parse(i.Value))
.FirstOrDefault();
The cast double? is necessary, otherwise FirstOrDefault will return 0.0 for empty collection, which might be ambiguous.
I have statements like this all over the place.
Since you are doing this multiple times, you may want to improve efficiency, rather than reducing the line count. One way to approach this would be extracting all fields into a Dictionary at once, and then quickly taking the items as needed:
var fieldNames = new Set<string> {
"Loan Amount", "Loan Balance", "Amount Due"
};
var dict = ll
.Fields
.Where(f => fieldNames.Contains(f.FieldTitle))
.ToDictionary(f => f.FieldTitle, f => double.Parse(f.Value));
dict.TryGetValue("Loan Amount", out LatestItem.VelocifyLoanAmount);
dict.TryGetValue("Loan Balance", out LatestItem.VelocifyLoanBalance);
dict.TryGetValue("Amount Due", out LatestItem.VelocifyAmountDue);
You can do something like:
var item = ll.Fields.Where(x = > x.FieldTitle == "Loan Amount").FirstOrDefault();
return (item != null) ? item.Value : DefaultReturnValue;
The return uses a tertiary operator. The first value is a boolean check. If the boolean is true then the value after the "?" is returned. Else, the value after the ":" is returned;

Some difficulties writing a LINQ query

I have the following code:
IsServiceable = _context.Review.Any(r => r.SiteId == x.Id) ? _context.Review.All(r => r.SiteId == x.Id && r.IsValid == true) : true
But as you can see it is not effective because I try to access the database twice in the same row.
I need to write single query(LINQ TO ENTITY) to check if the table named Reviews
has at least one row
where siteId=5 if it doesn't it has to return true,
If table Reviews has at least one row I need to check a boolean column named isValid if, there is at least one row where siteId=5 and isValid column is false I need to return false.
I believe your solution lies in the fact that only in one case do you need to return false - everything else returns true. Therefore, if you find one row where sideId=5 and isValid = false, then return false. Otherwise, return true. Based on your code, I suggest something like the following:
IsServiceable = _context.InspectionReview.Any(r => r.SiteId == x.Id && r.isValid == false) ? false : true;
You most likely have navigation properties so you could try
IsServiceable = _context.Site.Any(s => s.Id == x.Id && s.Reviews.Any(r => r.IsValid));

using one line if in linq statement

I have multiple drop-down lists with default value of 0 which indicates that user not selected any option and other numbers with mean user selected an value and it should include in LINQ query. My problem is I can not check if the user selected any options in drop-down lists or not?
This is my try for first drop-down list:
var ddl1 = Convert.ToInt32(ddlDastgAhasli.SelectedValue);
var project = (from p in context.Projects
where Convert.ToInt32(p.DastgahEjraeiAsli) == ((ddl1 == 0) ? null : ddl1) select p);
This is the error:
type of conditional expression cannot be determined because there is no implicit conversation '' and 'int'
You have two problems here:
You cant compare a value type(in your case int) to null.
You need to select something.
This is the structure for the query:
var project = (from p in context.Projects where p.prop == 1 select p);
And this to parse the int:
Bad
string strInt = "7";
if(Convert.ToInt32(strInt) == null) // compilation error
Good
string strInt = "7";
int intVal;
if(int.TryParse(strInt, out intVal))
{
// intVal is an integer
}
else
{
// intVal isnt an integer
}
If you just want to skip the where condition when ddl1 isn't set, you can just conditionally add the where clause when actually needed, something like (with the somewhat silly example of all ddls comparing to the same field)
var project = (from p in context.Projects select p);
if(ddl1 != 0)
{
project = project.Where(Convert.ToInt32(p.DastgahEjraeiAsli) == ddl1);
}
if(ddl2 != 0)
{
project = project.Where(Convert.ToInt32(p.DastgahEjraeiAsli) == ddl2);
}
...
This will effectively require all where clauses where ddlx != 0 to be true, and the ones where the ddl is 0 are not in any way affecting the query.
Here is a very useful extension method which i use in my projects to solve various checks..Its not about only ASP.NET..You can use it in winforms etc. also
public IEnumerable<Control> GetAll(Control control)
{
var controls = control.Controls.Cast<Control>();
return controls.SelectMany(ctrl => GetAll(ctrl))
.Concat(controls)
.Where(c => c.Visible == true);
//If you don't need to check that the control's visibility then simply ignore the where clause..
}
with this method no matter your control (in your situation dropdownlists) is a member/child of another control under that control which the control you pass as parameter to the method..Method checks recursively started from given parameter and checks all child controls related to given control as Method parameter..
And Usage in code :
//Its Assumed you need to check DropDownList' SelectedIndex property
List<Control> dropDownsOfPageWhichTheirSelectedIndexIsZero
= new List<Control>( GetAll ( YourAspNetPage )
.Where( x => x is DropDownList
&& ( ( DropDownList ) x ) . SelectedIndex == 0 ) ) ;
// Lets check if our page has dropdowns which their SelectedIndex equals to Zero
if ( dropDownsOfPageWhichTheirSelectedIndexIsZero . Count > 0 )
{
// do your work what you need in your project
//suppose you need their names and do something with this name (i.e.warn a message to user)
foreach ( DropDownList ddl in dropDownsOfPageWhichTheirSelectedIndexIsZero )
{
alert ("Please Check "+ ddl.Name +".Should Chost other than \"Select\" option");
}
}
Hope this Helps..
problem solved by putting "Convert.ToInt32(p.DastgahEjraeiAsli)" instead of null, so if the ddl1 == 0 (user hasn't selected any item) where skips.
var project = (from p in context.Projects
where Convert.ToInt32(p.DastgahEjraeiAsli) == ((ddl1 == 0) ? Convert.ToInt32(p.DastgahEjraeiAsli) : ddl1) select p);
this is very useful when for example u have a search form with multiple texboxs and dropdownlists and user may choose each of them and you do not know which one will be selected and which one not.
simplified example :
in the search button click event:
int ddl1 = Convert.ToInt32(dropdownlist1.selectedvalue);
int ddl2 = Convert.ToInt32(dropdownlist2.selectedvalue);
string txt1 = textbox1.text;
var project = (from p in context.mytable
where p.field1 == ((ddl1 == 0) ? p.field1 : ddl1)
&& p.field2 == ((ddl2 == 0) ? p.field2 : ddl2)
&& p.field3 == ((txt1 == "") ? p.field3 : txt1)
select p).ToList();
gridview1.datasource = project;
fridview1.databind();
not: each dropdownlist has a default value with text="select an item" and value="0", so if user didn't select any option default value remains 0.

How to query a C# dictionary and return a specific set of values

I have a dictionary in my C# program that contains a list of Key + Values.
The values are itemid, Month, Year, Count
I would like to query the dictionary by comparing a set of values (itemid, Month, Year) and return true or false if a the specific itemid + Month + Year exist.
So if all 3 values (itemid + Month + Year) exist return true else return false.
I tried something like this
(if (myd.Select(d => d.Value.itemid == item.itemid && d.Value.Month == DateRange.Month && d.Value.Year == DateRange.Year).ToString() != "")
The above didn't work.
You seem to misunderstand the usage of the Select() method. Select creates a "projection"; given an input collection (enumerable) of elements, it produces an output enumerable that is equal in cardinality, but is composed of elements that are each the result of a transformation of the corresponding element of the input.
What you need is either a Where() method (which returns a list, lesser or equal in cardinality to the input, of the elements from the input for which a boolean condition is true), or an Any() method (which returns a single "true" or "false" if any of the elements in the input meet the condition):
if(myd.Where(d => d.Value.itemid == item.itemid
&& d.Value.Month == DateRange.Month
&& d.Value.Year == DateRange.Year).Count() >= 1)
...
//produces the equivalent result but generally performs faster
if(myd.Any(d => d.Value.itemid == item.itemid
&& d.Value.Month == DateRange.Month
&& d.Value.Year == DateRange.Year))
...
If like linq-Syntax, this checks if at least one item that satisfies all three condition exists:
if((from d in myd
where d.Value.itemid == item.itemid
&& d.Value.Month == DateRange.Month
&& d.Value.Year == DateRange.Year).FirstOrDefault() != null)
You'll need to create a 2nd dictionary if you want to do lookups with another key (in this case itemid,month,year, probably placed into a Tuple), and you'll need to maintain them both whenever you add/remove from either.
use Where to filter (I'm assuming the condition in your code is defined correctly... you haven't given us enough info to evaluate that)
var filteredDictionary = myd.Where(d => d.Value.itemid == item.itemid && d.Value.Month == DateRange.Month && d.Value.Year == DateRange.Year)
use Select to transform from a KeyValuePair to just a value
var filteredValues = filteredDictionary.Select(x=>x.Value)
use Any to return a bool of whether or not an item exists
bool matchExists = myd.Any(d => d.Value.itemid == item.itemid && d.Value.Month == DateRange.Month && d.Value.Year == DateRange.Year)
Any is going to be most efficient for the problem you describe because it will stop evaluating items in the dictionary and return True as soon as a match is found
If you are working with .NET 4.0 you can use Tuples as keys.
var dict = new Dictionary<Tuple<int,int,int>,MyValueType>();
You can then test if a value exists with
var key = new Tuple<int,int,int>(item.itemid, DateRange.Month, DateRange.Year);
if(dict.ContainsKey(key)) {
...
}
Or you can test
if(dict.ContainsValue(referenceValue)) {
...
}
You will have to pass it a reference value containing what you are looking for. Make sure that your value type implements EqualityComparer<T>.
The first method will be much faster, since the dictionary is accessed by the key. If you are not accessing the dictionary by the key, you could use a List<T> as well.

Categories