Distinct the collection in Linq C# - c#

I have the collection
From the collection the column name ma_position_value should not contain the same value
For Example
If the collection have 5 records, The column ma_position_value should not contain the same value from all 5 records...but it can contain same value for 2 or 3 or 4 records from the collection Atleast one column value should change.
So the main intension is ALL 5 records should not contain same value.Any one should get different value.So if all 5 is same I tried to throw a message
So I have just write a bool to return it if it is change
bool lblMa = false;
lblMa = ibusCalcWiz.iclbMssPaServiceSummary
.Where(lbusMssPaServiceSummary => lbusMssPaServiceSummary.icdoSummary.ma_position_value.IsNotNullOrEmpty()).Distinct().Count() > 1;
But it is always return true.

Just select distinct ma_position_value property values:
bool allSame = ibusCalcWiz.iclbMssPaServiceSummary
.Select(i => i.ma_position_value)
.Distinct()
.Count() == 1;
HINT: Do not use long variable names in lambda expressions. There is a rule of thumb - the bigger scope of variable usage, the bigger should be name. If scope is very small (lambda expression) then name should be very small (single letter is enough).

You can get the first one, and check if they are all equal:
// Only works if the collection is non-empty!
string first_ma_position_value = ibusCalcWiz.iclbMssPaServiceSummary.First().ma_position_value;
bool allTheSame = ibusCalcWiz.iclbMssPaServiceSummary
.All(lbusMssPaServiceSummary.icdoSummary.ma_position_value == first_ma_position_value);
or you can do the distinct, as you originally wanted, but on the value of the column instead of on the objects
bool allTheSame = ibusCalcWiz.iclbMssPaServiceSummary
.Select(lbusMssPaServiceSummary => lbusMssPaServiceSummary.icdoSummary.ma_position_value)
.Distinct()
.Count() == 1;

Related

USe LINQ to remove from a list based on conditions

I have a list 'nList' returned from a LINQ query. The data is correct but I have to check if the data in the 2nd field ('nType') occurs more than once, and if it does, remove it from the list if the 3rd field ('nAmount') is null.
To illustrate, in the example below, I would want to remove the record with ID 2.
Can this be done using LINQ?
EDIT: There can only be 2 scenarios:
one occurrence of nType, with nAmount populated
two occurences of nType, with one nAmount populated, the other nAmount null
ID nType nAmount
1 A 12.00
2 A
3 B 13.00
4 C 14.00
var result = nList.Where(x => x.nAmount != null).DistinctBy(x => x.nType);
You would need to install MoreLinq from Nuget to get the DistinctBy().
This can be done with a GroupBy overload which lets you define the grouped object
var result = nList.GroupBy(
x => x.nType,
(key,g) => new {
ID = g.First(x => x.nAmount != null).ID,
nType = key,
nAmount = g.First(x => x.nAmount != null).nAmount }
);
Live example: http://rextester.com/PFX41986
This has a few caveats
If your resultset has a single nType which has a null nAmount it will not appear in the results
If you get more than 1 distinct nType with a non-null nAmount this will take the first one.

How do I check the values retrieved from this Linq query as .ToLower()?

This is my code:
DataRow r = VirtualTable
.AsEnumerable()
.FirstOrDefault(tt => (tt.Field<string>("Column1") == value1) ||
(tt.Field<string>("Column1") == value2));
This code retrieves a data row whose 'Column1' matches a given string. I then check this against a bool if statement. However, though I can change my string's capitalization, I don't know how to handle it with the value Linq gives me. Still learning linq, so I don't know my way around it yet.
In short, I have the string "Red box" in the table, but want it to be read as "red box" so it will match my internal string of the same value.
Additionally, I was trying to retrieve the IndexOf the row this query gives me, but I'm always retrieving a -1 even if it finds a match.
Here's the code to retrieve it:
int SelectedIndex = VirtualTable.Rows.IndexOf(r);
Try string.Equals to ignore case and overload Select to get row's index:
var row = VirtualTable
.AsEnumerable()
.Select((tt, index) => new {
value = tt.Field<string>("Column1"),
index = index})
.FirstOrDefault(item =>
string.Equals(item.value, value1, StringComparison.OrdinalIgnoreCase) ||
string.Equals(item.value, value2, StringComparison.OrdinalIgnoreCase));
// If we have the row found, we can get
if (row != null) {
var r = row.value; // value, e.g. "bla-bla-bla"
int selectedIndex = row.index; // as well as its index, e.g. 123
...
}
You can use String.Equals(string,StringComparisonOption) to compare two strings using case-insensitive comparison. This avoids generating yet-another-temporary-string as ToLower() would do, eg:
tt.Field<string>("Column1").Equals(value1,StringComparison.OrdinalIgnoreCase)
or
tt.Field<string>("Column1").Equals(value1,StringComparison.CurrentCultureIgnoreCase)
Make sure you use the appropriate comparison option. Different cultures have different casing rules. Ordinal is the fastest option as it compares strings using binary rules.

Count predicate, how does it work?

With a linq query I retrieve a list from the database. The list contains 2 items of a specific class containing the property RoleType. the type of RoleType is an int.
the first object has a property value 0.
the second object has a property value 1.
I also got an enum:
enum RoleTypes
{
Type1 = 1,
Type2 = 0,
}
The weird order of indexing the enums is a given, I can't change that.
My business rules states that there has to be exactly one role with RoleType value Type2 and at least one role with RoleType value Type1. This is the code I use for that:
var ExactlyOneRoleType2 = roles.Count(role => role.RoleType == (int)RoleTypes.Type2) == 1;
var AtLeastOneRoleType1 = roles.Any(role => role.RoleType == (int)RoleTypes.Type1);
According to the list I mentioned earlier, both variables (ExactlyOneRoleType2 and AtLeastOneRoleType1) should be true. At least, I would expect that. Only if I debug through the code I found out that ExactlyOneRoleType2 is false. After some research I find out that
roles.Count(role => role.RoleType == (int)RoleTypes.Type2)
returns 2 instead of 1 which I find odd because there is only 1 role with RoleType Type2. Why does the count return 2? It also doesn't compute with the fact that the Any call actually returns true. How can list containing 2 items have both 2 items with RoleType Type2 and have at least one item with RoleType Type1?
Also when I change the count call to
roles.Count(role => role.RoleType == 0)
it still returns 2. Only when I change the Count call to this:
private static bool IsRoleTypeType2(Role role)
{
return role.RoleType == (int)RoleTypes.Type2;
}
roles.Count(IsRoleTypeType2)
the count returns 1 as it should be.
What is happening here? Why does the count return 2 when I use a anonymous predicate? Did I misunderstood something about how the predicate works in case of count? Or is this is bug in Linq?

Search in part of the list by LINQ

I want to know if there's a way to search from a specific index in LINQ
This is what i want to do for example :
//search after the 4th element if exist any true
bool result = myList.Any(a=>a.flagTodo)
// in my case I want to do like: myList.where(a=>a.index >4).Any(a=>a.flagTodo)
there's any way to do it in the same linq ?
You can use Enumerable.Skip to bypass specified number of elements in sequence:
bool result = myList.Skip(4).Any(a => a.flagTodo);
BTW you don't need to verify list length - if there is less than 4 items, result will be false - Skip(4) will return empty sequence. And Any returns false because none of elements in sequence satisfies condition (sequence is empty).
You can skip the first 4 elements.
bool result = myList.Skip(4).Any(a => a.flagTodo);
But you need to check on your list length first before calling this statement.
Either use Skip as others have mentioned or pass the index so that you can use it in Any
bool result = myList.Select((obj, index) => new { obj, index })
.Any(x => x.index > 4 && x.obj.flagTodo);

c# filter search, multiple searchboxes

List<LICENSE> licenseList = context.LICENSE.Where(l => ( string.IsNullOrEmpty(licenseID) || l.LICENSE_ID.Contains(licenseID) ) && ( string.IsNullOrEmpty(hardwareID) || l.HARDWARE_ID.Contains(hardwareID) ) ).Take(10).ToList();
This is my current solution for handling more than one searchbox. Its a search function that combines 2 or more textfields in to a search. So my questions are: Is this an ok way to filter out the passed searchstrings. And how do i use it when the queries are decimals instead of strings? Thanks
Your example is perfectly fine.
With regards to it being decimals:
If it is a nullable type, then you first have to check if it has a value, and if it has that it is not the default value for a decimal which is 0.
If it is not a nullable type, then all you have to do is check that it is/is not == to 0 which is the default type. I always just check to make sure it's greater than zero, based on the assumption that a license won't be negative.
I am going to assume that it's not a nullable type as it seems to be an inline declared var, so here is a formatted example for decimal:
List<LICENSE> licenseList =
context.LICENSE.Where(l => licenseID == 0 || l.LICENSE_ID.Contains(licenseID))
.Where(l => hardwareID == 0 || l.HARDWARE_ID.Contains(hardwareID))
.Take(10)
.ToList();
Interesting thing to note, if you don't know the default type of a field, you can always do
licenseID == default(decimal)
You may try using a foreach loop on the search boxes, modifying linq, for any of those.
object[] a = {"seach", 5}; // "Data"
string[] Search = { "asdf", "asdf" }; //Search boxes
var s = a.Where(l => ((string)l).Contains(Search[0])); //first search
for (int i = 1; i < Search.Length; i++) //consecutive searches
s = s.Where(l => ((string)l).Contains(Search[i]));
Yes it looks ok. You could also use a loop somehow like this:
var query = context.LICENSE;
foreach(var item in stringVariables) {
query = query.Where(x => string.IsNullOrEmpty(item) || l.LICENSE_ID.Contains(item));
}
and stringVariables can be predefined or some algorithm to decide whether it's a search field or not.
Concerning the numbers (and assuming your column has type int, if it is a string you don't have to change anything), you probably have a nullable number, depending on your search form. So, you also have to check whether it's null or not and whether it's the right number. You may want to cast it to a string to also have the Contains function. But that all depends on your application.

Categories