Comparing strings in LINQ - c#

I am using a LINQ Query, which is not working some times.
Few times it work, but few times i do not get my answer.
The query is
int a=0;
if (!Projects.Any(p => p.ID.Equals(PID)))
{
a = 0;
}
else
{
a= 10;
}
Here, Projects is an Enumerable of a class where it contains ID. So, even if there is an item which is same as PID, it wont come inside the ELSE loop.
I debugged it and saw that there is 10 count of Projects and 1 item is having an ID same as PID, but still its not coming in the ELSE loop.
PID and ID are Strings.
Why is this not working ?
I even tried :
if (!Projects.Any(p => p.ID==PID))
Updated:
I want to go in the Else loop.

Are you sure you don't want:
if (Projects.Any(p => p.ID.Equals(PID)))
The way you have it currently, it will only go inside the block if none of the IDs is equal to PID.
If you are actually trying to get it to go into the else block, then I would suggest taking into consideration what Eric Lippert said and trim off any whitespace that might be there:
PID = PID.Trim();
if (!Projects.Any(p => p.ID != null && p.ID.Trim().Equals(PID)))
And if that still doesn't work, inspect the values in the debugger for any anomalies that the values might have.

Related

LINQ Select n list ASP.NET Core

I have this code:
foreach(var i in category.count)
{
var getDifferentSerialNumberforEachLoop = _db.Category.Where(a => a.CategoryID ==
categoryID).Select(i=>i.SerialNumber).FirstOrDefault();
//Proceed to do something else with the first serial number value
.....
///end of the first serial number being processed, do again n times (number of categry.count
times)
}
So you have a case where a CategoryID can have many SerialNumbers associated with it,
Example:
CategoryID SerialNumber
12345 0123445
12345 2345678
12345 0987654
12345 8756478
.... ......(n times)
I want to loop through and get each of those serial number and save to the variable, 'getDifferentSerialNumberforEachLoop' process that separately and do it again for all serial numbers associated with that CategoryID. But at the moment I'm only getting the first SerialNumber say 0123445 of course this is because I'm using 'FirstOrDefault()' so even though the Select(i=>i.SerialNumber) value changes each time it loops through category.count the variable, getDifferentSerialNumberforEachLoop will always be the firstordefault value.
My question is: how do I make the getDifferentSerialNumberforEachLoop to always have the next SerialNumber value?
I can't use .Take(4) because I don't know if category.count will always be 4 - if that make sense?
Can't use LastOrDefault because I wouldn't get the first to the last values, I can't use List() because I only want one SerialNumber value at a time.
So is there a way I could go about this? I've also seen Takewhile but not sure about that? Any other query I could use for this please? Thank you.
I'd Suggest something like the below.
foreach(var i in category.count)
{
var getDifferentSerialNumberforEachLoop = _db.Category.Where(a => a.CategoryID ==
categoryID).Select(i=>i.SerialNumber).ToList().ForEach(serialNo => {
Console.WriteLine(serialNo);
});
}
You say you "cannot use List because you need one Serial Number at a time" but doing ToList() and ForEach will allow you to iterate over each Serial Number at a time.

EF - A proper way to search several items in database

I have about 100 items (allRights) in the database and about 10 id-s to be searched (inputRightsIds). Which one is better - first to get all rights and then search the items (Variant 1) or to make 10 checking requests requests to the database
Here is some example code:
DbContext db = new DbContext();
int[] inputRightsIds = new int[10]{...};
Variant 1
var allRights = db.Rights.ToLIst();
foreach( var right in allRights)
{
for(int i>0; i<inputRightsIds.Lenght; i++)
{
if(inputRightsIds[i] == right.Id)
{
// Do something
}
}
}
Variant 2
for(int i>0; i<inputRightsIds.Lenght; i++)
{
if(db.Rights.Any(r => r.Id == inputRightsIds[i]);)
{
// Do something
}
}
Thanks in advance!
As other's have already stated you should do the following.
var matchingIds = from r in db.Rights
where inputRightIds.Contains(r.Id)
select r.Id;
foreach(var id in matchingIds)
{
// Do something
}
But this is different from both of your approaches. In your first approach you are making one SQL call to the DB that is returning more results than you are interested in. The second is making multiple SQL calls returning part of the information you want with each call. The query above will make one SQL call to the DB and return only the data you are interested in. This is the best approach as it reduces the two bottle necks of making multiple calls to the DB and having too much data returned.
You can use following :
db.Rights.Where(right => inputRightsIds.Contains(right.Id));
They should be very similar speeds since both must enumerate the arrays the same number of times. There might be subtle differences in speed between the two depending on the input data but in general I would go with Variant 2. I think you should almost always prefer LINQ over manual enumeration when possible. Also consider using the following LINQ statement to simplify the whole search to a single line.
var matches = db.Rights.Where(r=> inputRightIds.Contains(r.Id));
...//Do stuff with matches
Not forget get all your items into memory to process list further
var itemsFromDatabase = db.Rights.Where(r => inputRightsIds.Contains(r.Id)).ToList();
Or you could even enumerate through collection and do some stuff on each item
db.Rights.Where(r => inputRightsIds.Contains(r.Id)).ToList().Foreach(item => {
//your code here
});

Find and change the value of first element in list that meets a requirement, do something else if not found

This seems to be ridiculously easy, but I just can't seem to find a way to do it. Basically the title, I want to find the first item in my list that meets a requirement, and modify the value of that found item, and if none of the items in that list meets it, then do something else.
I was using a foreach loop to this, but it is definitely not the fastest way.
foreach (CustomClass foo in bar)
{
if (!foo.Value)
{
foo.Value = true;
currentCount++;
break;
}
}
I then tried to use List.First() and catching the exception when it can't find the value, but that is far slower, and I'm looking for performance.
EDIT: Never mind about what is below, I found how to make first or default work, but is there a faster way to do this multiple times than the foreach method? Thanks
So I tried FirstOrDefault, but I keep getting null reference exception
if (bar.FirstOrDefault(c => c.Value == false).Equals(null))
{
break;
}
else
{
thePicture.FirstOrDefault(c => c.Value == false).Value = true;
currentCount++;
}
Anyone know how to make the first or default work? Or is there any other way to do this faster than the foreach method. (This will be ran in another loop a lot of times) Thanks!
FirstOrDefault will return a null reference if no element is found - assuming the element type is a reference type. Instead of calling Equals on the result, just use ==... and don't call it twice:
var first = bar.FirstOrDefault(c => !c.Value);
if (first == null)
{
...
}
else
{
// Use first, I suspect.
// (You don't in the sample code, but...)
}
Note that this won't be faster than an appropriate foreach loop, but it can be more readable.
(bar!=null)?((bar[1].value == true)?(do something):(do something)):do something)
Here you are only checking the first element in list right?
So why going for a loop.

A better way to loop through lists

So I have a couple of different lists that I'm trying to process and merge into 1 list.
Below is a snipet of code that I want to see if there was a better way of doing.
The reason why I'm asking is that some of these lists are rather large. I want to see if there is a more efficient way of doing this.
As you can see I'm looping through a list, and the first thing I'm doing is to check to see if the CompanyId exists in the list. If it does, then I find item in the list that I'm going to process.
pList is my processign list. I'm adding the values from my different lists into this list.
I'm wondering if there is a "better way" of accomplishing the Exist and Find.
boolean tstFind = false;
foreach (parseAC item in pACList)
{
tstFind = pList.Exists(x => (x.CompanyId == item.key.ToString()));
if (tstFind == true)
{
pItem = pList.Find(x => (x.CompanyId == item.key.ToString()));
//Processing done here. pItem gets updated here
...
}
Just as a side note, I'm going to be researching a way to use joins to see if that is faster. But I haven't gotten there yet. The above code is my first cut at solving this issue and it appears to work. However, since I have the time I want to see if there is a better way still.
Any input is greatly appreciated.
Time Findings:
My current Find and Exists code takes about 84 minutes to loop through the 5.5M items in the pACList.
Using pList.firstOrDefault(x=> x.CompanyId == item.key.ToString()); takes 54 minutes to loop through 5.5M items in the pACList
You can retrieve item with FirstOrDefault instead of searching for item two times (first time to define if item exists, and second time to get existing item):
var tstFind = pList.FirstOrDefault(x => x.CompanyId == item.key.ToString());
if (tstFind != null)
{
//Processing done here. pItem gets updated here
}
Yes, use a hashtable so that your algorithm is O(n) instead of O(n*m) which it is right now.
var pListByCompanyId = pList.ToDictionary(x => x.CompanyId);
foreach (parseAC item in pACList)
{
if (pListByCompanyId.ContainsKey(item.key.ToString()))
{
pItem = pListByCompanyId[item.key.ToString()];
//Processing done here. pItem gets updated here
...
}
You can iterate though filtered list using linq
foreach (parseAC item in pACList.Where(i=>pList.Any(x => (x.CompanyId == i.key.ToString()))))
{
pItem = pList.Find(x => (x.CompanyId == item.key.ToString()));
//Processing done here. pItem gets updated here
...
}
Using lists for this type of operation is O(MxN) (M is the count of pACList, N is the count of pList). Additionally, you are searching pACList twice. To avoid that issue, use pList.FirstOrDefault as recommended by #lazyberezovsky.
However, if possible I would avoid using lists. A Dictionary indexed by the key you're searching on would greatly improve the lookup time.
Doing a linear search on the list for each item in another list is not efficient for large data sets. What is preferable is to put the keys into a Table or Dictionary that can be much more efficiently searched to allow you to join the two tables. You don't even need to code this yourself, what you want is a Join operation. You want to get all of the pairs of items from each sequence that each map to the same key.
Either pull out the implementation of the method below, or change Foo and Bar to the appropriate types and use it as a method.
public static IEnumerable<Tuple<Bar, Foo>> Merge(IEnumerable<Bar> pACList
, IEnumerable<Foo> pList)
{
return pACList.Join(pList, item => item.Key.ToString()
, item => item.CompanyID.ToString()
, (a, b) => Tuple.Create(a, b));
}
You can use the results of this call to merge the two items together, as they will have the same key.
Internally the method will create a lookup table that allows for efficient searching before actually doing the searching.
Convert pList to HashSet then query pHashSet.Contains(). Complexity O(N) + O(n)
Sort pList on CompanyId and do Array.BinarySearch() = O(N Log N) + O(n * Log N )
If Max company id is not prohibitively large, simply create and array of them where item with company id i exists at i-th position. Nothing can be more fast.
where N is size of pList and n is size of pACList

Looping on IEnumerator<T>, Any Suggestions

I am having a situation where looping through the result of LINQ is getting on my nerves. Well here is my scenario:
I have a DataTable, that comes from database, from which I am taking data as:
var results = from d in dtAllData.AsEnumerable()
select new MyType
{
ID = d.Field<Decimal>("ID"),
Name = d.Field<string>("Name")
}
After doing the order by depending on the sort order as:
if(orderBy != "")
{
string[] ord = orderBy.Split(' ');
if (ord != null && ord.Length == 2 && ord[0] != "")
{
if (ord[1].ToLower() != "desc")
{
results = from sorted in results
orderby GetPropertyValue(sorted, ord[0])
select sorted;
}
else
{
results = from sorted in results
orderby GetPropertyValue(sorted, ord[0]) descending
select sorted;
}
}
}
The GetPropertyValue method is as:
private object GetPropertyValue(object obj, string property)
{
System.Reflection.PropertyInfo propertyInfo = obj.GetType().GetProperty(property);
return propertyInfo.GetValue(obj, null);
}
After this I am taking out 25 records for first page like:
results = from sorted in results
.Skip(0)
.Take(25)
select sorted;
So far things are going good, Now I have to pass this results to a method which is going to do some manipulation on the data and return me the desired data, here in this method when I want to loop these 25 records its taking a good enough time. My method definition is:
public MyTypeCollection GetMyTypes(IEnumerable<MyType> myData, String dateFormat, String offset)
I have tried foreach and it takes like 8-10 secs on my machine, it is taking time at this line:
foreach(var _data in myData)
I tried while loop and is doing same thing, I used it like:
var enumerator = myData.GetEnumerator();
while(enumerator.MoveNext())
{
int n = enumerator.Current;
Console.WriteLine(n);
}
This piece of code is taking time at MoveNext
Than I went for for loop like:
int length = myData.Count();
for (int i = 0; i < 25;i++ )
{
var temp = myData.ElementAt(i);
}
This code is taking time at ElementAt
Can anyone please guide me, what I am doing wrong. I am using Framework 3.5 in VS 2008.
Thanks in advance
EDIT: I suspect the problem is in how you're ordering. You're using reflection to first fetch and then invoke a property for every record. Even though you only want the first 25 records, it has to call GetPropertyValue on all the records first, in order to order them.
It would be much better if you could do this without reflection at all... but if you do need to use reflection, at least call Type.GetProperty() once instead of for every record.
(In some ways this is more to do with helping you diagnose the problem more easily than a full answer as such...)
As Henk said, this is very odd:
results = from sorted in results
.Skip(0)
.Take(25)
select sorted;
You almost certainly really just want:
results = results.Take(25);
(Skip(0) is pointless.)
It may not actually help, but it will make the code simpler to debug.
The next problem is that we can't actually see all your code. You've written:
After doing the order by depending on the sort order
... but you haven't shown how you're performing the ordering.
You should show us a complete example going from DataTable to its use.
Changing how you iterate over the sequence will not help - it's going to do the same thing either way, really - although it's surprising that in your last attempt, Count() apparently works quickly. Stick to the foreach - but work out exactly what that's going to be doing. LINQ uses a lot of lazy evaluation, and if you've done something which makes that very heavy going, that could be the problem. It's hard to know without seeing the whole pipeline.
The problem is that your "results" IEnumerable isn't actually being evaluated until it is passed into your method and enumerated. That means that the whole operation, getting all the data from dtAllData, selecting out the new type (which is happening on the whole enumerable, not just the first 25), and then finally the take 25 operation, are all happening on the first enumeration of the IEnumerable (foreach, while, whatever).
That's why your method is taking so long. It's actually doing some of the work defined elsewhere inside the method. If you want that to happen before your method, you could do a "ToList()" prior to the method.
You might find it easier to adopt a hybrid approach;
In order:
1) Sort your datatable in-situ. It's probably best to do this at the database level, but, if you can't, then DataTable.DefaultView.Sort is pretty efficient:
dtAllData.DefaultView.Sort = ord[0] + " " + ord[1];
This assumes that ord[0] is the column name, and ord[1] is either ASC or DESC
2) Page through the DefaultView by index:
int pageStart = 0;
List<DataRowView> pageRows = new List<DataRowView>();
for (int i = pageStart; i < dtAllData.DefaultView.Count; i++ )
{
if(pageStart + 25 > i || i == dtAllData.DefaultView.Count - 1) { break; //Exit if more than the number of pages or at the end of the rows }
pageRows.Add(dtAllData.DefaultView[i]);
}
...and create your objects from this much smaller list... (I've assumed the columns are called Id and Name, as well as the types)
List<MyType> myObjects = new List<MyType>();
foreach(DataRowView pageRow in pageRows)
{
myObjects.Add(new MyObject() { Id = Convert.ToInt32(pageRow["Id"]), Name = Convert.ToString(pageRow["Name"])});
}
You can then proceed with the rest of what you were doing.

Categories

Resources