I have a list of action type objects. Each object has a list of departments.
I have a user and a user object has n number of deparments.
I would like to get a list of user actions that the user can take. Here is what I came up with:
List<Item> userActions = new List<Item>();
foreach (var actionType in actionTypelist)
{
foreach (var dept in actionType.availableDepts)
{
if (data.currentUser.secondaryServDepts.Where(x => x.Id == dept.servDeptId).Count() > 0)
{
userActions.Add(actionType);
}
}
}
Can you please suggest a better way to get a quicker result? Thanks in advance.
One possible optimisation instead of:
if (data.currentUser.secondaryServDepts.Where(x => x.Id == dept.servDeptId).Count() > 0)
{
userActions.Add(actionType);
}
Use:
if (data.currentUser.secondaryServDepts.Any(x => x.Id == dept.servDeptId))
{
userActions.Add(actionType);
}
Count will enumerate the entire collection while Any will stop at the first match (since all you need is at least one item)
Related
I would like to request you to help me with this problem. I have an Observable Collection that stores favourites and I load items to another Observable Collection, so, what I want is for the new items which have unique IDs to be checked against Favourites Observable Collection in an efficient way as I feel what I am doing is not good enough.
What I am currently doing is as follows:
foreach (var item in AllItems)
{
if (Watchlist.Fav.Count != 0)
{
if (Watchlist.Fav.Any(s => s.Id == item.Id)))
{
Watchlist.Fav.Remove(Watchlist.Fav.SingleOrDefault(i => i.Id == item.Id));
Watchlist.Fav.Add(item);
item.IsFavorite = true;
ItmesCollection.Add(item);
}
}
}
Could someone please help me make this better?
Cheers guys!
Since OP is asking a better syntax of current working code. Here is a try:
foreach (var item in AllItems)
{
// no need check Watchlist.Fav.Count, because .Any duplicates
// store matchingFav in variable so no need query twice
var matchingFav = Watchlist.Fav.SingleOrDefault(s => s.Id == item.Id)));
if (matchingFav != null)
{
matchingFav.IsFavorite = true;
// where is ItemsCollection from? background not clear, so no change
ItemsCollection.Add(item);
}
}
If the last statement is not relavant, syntax can be even shorter:
var ids = new HashSet<int>(AllItems.Select(x => x.Id));
foreach (var matchingFav in Watchlist.Fav
.Where(x => ids.Contains(x.Id)))
{
matchingFav.IsFavorite = true;
}
I want to create a loop to check a list of titles for duplicates.
I currently have this:
var productTitles = SeleniumContext.Driver.FindElements(By.XPath(ComparisonTableElements.ProductTitle));
foreach (var x in productTitles)
{
var title = x.Text;
productTitles = SeleniumContext.Driver.FindElements(By.XPath(ComparisonTableElements.ProductTitle));
foreach (var y in productTitles.Skip(productTitles.IndexOf(x) + 1))
{
if (title == y.Text)
{
Assert.Fail("Found duplicate product in the table");
}
}
}
But this is taken the item I skip out of the array for the next loop so item 2 never checks it's the same as item 1, it moves straight to item 3.
I was under the impression that skip just passed over the index you pass in rather than removing it from the list.
You can use GroupBy:
var anyDuplicates = SeleniumContext
.Driver
.FindElements(By.XPath(ComparisonTableElements.ProductTitle))
.GroupBy(p => p.Text, p => p)
.Any(g => g.Count() > 1);
Assert.That(anyDuplicates, Is.False);
or Distinct:
var productTitles = SeleniumContext
.Driver
.FindElements(By.XPath(ComparisonTableElements.ProductTitle))
.Select(p => p.Text)
.ToArray();
var distinctProductTitles = productTitles.Distinct().ToArray();
Assert.AreEqual(productTitles.Length, distinctProductTitles.Length);
Or, if it is enough to find a first duplicate without counting all of them it's better to use a HashSet<T>:
var titles = new HashSet<string>();
foreach (var title in SeleniumContext
.Driver
.FindElements(By.XPath(ComparisonTableElements.ProductTitle))
.Select(p => p.Text))
{
if (!titles.Add(title))
{
Assert.Fail("Found duplicate product in the table");
}
}
All approaches are better in terms of computational complexity (O(n)) than what you propose (O(n2)).
You don't need a loop. Simply use the Where() function to find all same titles, and if there is more than one, then they're duplicates:
var productTitles = SeleniumContext.Driver.FindElements(By.XPath(ComparisonTableElements.ProductTitle));
foreach(var x in productTitles) {
if (productTitles.Where(y => x.Text == y.Text).Count() > 1) {
Assert.Fail("Found duplicate product in the table");
}
}
I would try a slightly different way since you only need to check for duplicates in a one-dimensional array.
You only have to check the previous element with the next element within the array/collection so using Linq to iterate through all of the items seems a bit unnecessary.
Here's a piece of code to better understand:
var productTitles = SeleniumContext.Driver.FindElements(By.XPath(ComparisonTableElements.ProductTitle))
for ( int i = 0; i < productionTitles.Length; i++ )
{
var currentObject = productionTitles[i];
for ( int j = i + 1; j < productionTitles.Length; j++ )
{
if ( currentObject.Title == productionTitles[j].Title )
{
// here's your duplicate
}
}
}
Since you've checked that item at index 0 is not the same as item placed at index 3 there's no need to check that again when you're at index 3. The items will remain the same.
The Skip(IEnumerable, n) method returns an IEnumerable that doesn't "contain" the n first element of the IEnumerable it's called on.
Also I don't know what sort of behaviour could arise from this, but I wouldn't assign a new IEnumerable to the variable over which the foreach is being executed.
Here's another possible solution with LINQ:
int i = 0;
foreach (var x in productTitles)
{
var possibleDuplicate = productTitles.Skip(i++).Find((y) => y.title == x.title);
//if possibleDuplicate is not default value of type
//do stuff here
}
This goes without saying, but the best solution for you will depend on what you are trying to do. Also, I think the Skip method call is more trouble than it's worth, as I'm pretty sure it will most certainly make the search less eficient.
Scenario: In my business layer, I have this variable called "groups" which is list of 4 different groups. Business requirement is to display groups in such way so that you only view group which you are assigned to. Tricky part is that a person could be part of more than one group. I have the below logic which works perfect for AppAdmin because they are able to view all the groups.
if (IsUserInRole("Admin"))
{
groupsByMembersFirst = groupsByMembersFirst;
}
if (IsUserInRole("B"))
{
groupsByMembersFirst = groupsByMembersFirst.Where(g => g.GroupTypeName != "Bikes")
.ToList();
}
if (IsUserInRole("C"))
{
groupsByMembersFirst = groupsByMembersFirst.Where(g => g.GroupTypeName != "Cars")
.ToList();
}
if (IsUserInRole("N"))
{
groupsByMembersFirst = groupsByMembersFirst.Where(g => g.GroupTypeName != "NanoCars")
.ToList();
}
return groupsByMembersFirst;
groups contain all the 4 groups.
Here's what I need help with:
Currently if user is in role B and C, it will only show GroupTypeName cars because GroupTypeName List gets overwritten. How do I program it in such way that I just keep add/update the groupsByMembersFirst list so it does not overwrite it ? Help appreciated!
If I am not clear please let me know!
Do a separate list which will hold the groups, in if() add items to that list, and then return:
var returnVal = new List<Group>();
if (IsUserInRole("Admin"))
{
returnVal.AddRange(groupsByMembersFirst);
}
if (IsUserInRole("B"))
{
returnVal.AddRange(groupsByMembersFirst.Where(g => g.GroupTypeName != "Bikes"));
}
if (IsUserInRole("C"))
{
returnVal.AddRange(groupsByMembersFirst.Where(g => g.GroupTypeName != "Cars"));
}
if (IsUserInRole("N"))
{
returnVal.AddRange(groupsByMembersFirst.Where(g => g.GroupTypeName != "NanoCars"));
}
return returnVal;
You should consider inverting your options, going from least specific, to most specific ("Admin").
Start with a list and append with AddRange.
var validOptions = new List...
if (IsUserInRole("N"))
{
validOptions.AddRange(...)
}
I have a list of details about a large number of files. This list contains the file ID, last modified date and the file path. The problem is there are duplicates of the files which are older versions and sometimes have different file paths. I want to only store the newest version of a file regardless of file path. So I created a loop that iterates through the ordered list, checks to see if the ID is unique and if it is, it gets stored in a new unique list.
var ordered = list.OrderBy(x => x.ID).ThenByDescending(x => x.LastModifiedDate);
List<Item> unique = new List<Item>();
string curAssetId = null;
foreach (Item result in ordered)
{
if (!result.ID.Equals(curAssetId))
{
unique.Add(result);
curAssetId = result.ID;
}
}
However this is still allowing duplicates into the DB and I can't figure out why this code isn't working as expected. By duplicates I mean, the files have the same ID but different file paths, which like I said before shouldn't be an issue. I just want the latest version regardless of pathway. Can anyone else see what the issue is? Thanks
var ordered = listOfItems.OrderBy(x => x.AssetID).ThenByDescending(x => x.LastModifiedDate);
List<Item> uniqueItems = new List<Item>();
foreach (Item result in ordered)
{
if (!uniqueItems.Any(x => x.AssetID.Equals(result.AssetID)))
{
uniqueItems.Add(result);
}
}
this is what I have now and it is still allowing duplicates
This is because , you are not searching entire list to check whether the id is unique or not
List<Item> unique = new List<Item>();
string curAssetId = null; // here is the problem
foreach (Item result in ordered)
{
if (!result.ID.Equals(curAssetId)) // here you only compare the last value.
{
unique.Add(result);
curAssetId = result.ID; // You are only assign the current ID value and
}
}
to solve this , change the following
if (!result.ID.Equals(curAssetId)) // here you only compare the last value.
{
unique.Add(result);
curAssetId = result.ID; // You are only assign the current ID value and
}
to
if (!unique.Any(x=>x.ID.Equals(result.ID)))
{
unique.Add(result);
}
I don't know if this code is just simplified, but have you considered grouping on ID, sorting on LastModifiedDate, then just taking the first from each group?
Something like:
var unique = list.GroupBy(i => i.ID).Select(x => x.OrderByDescending(y => y.LastModifiedDate).First());
var ordered = list.OrderBy(x => x.ID).ThenByDescending(x => x.LastModifiedDate).Distinct() ??
For this purpose you have to create your own EquityComparer and after that you could use linq's Distinct method. Enumerable.Distinct at msdn
Also I think you could stay with your current code but you have to modify it in such a way (as a sample):
var ordered = list.OrderByDescending(x => x.LastModifiedDate);
var unique = new List<Item>();
foreach (Item result in ordered)
{
if (unique.Any(x => x.ID == result.ID))
continue;
unique.Add(result);
}
List<Item> p = new List<Item>();
var x = p.Select(c => new Item
{
AssetID = c.AssetID,
LastModifiedDate = c.LastModifiedDate.Date
}).OrderBy(y => y.id).ThenByDescending(c => c.LastModifiedDate).Distinct();
I have a list of employees, and all of them have another list nested which is called the DisplayList.
Now not all the employees have the same amount of DisplayFields. So I wish to get those with the highest DisplayFields, so that I can incorporate everyone in the display.
At the moment I have the following :-
int iMaxDisplayCount = 0;
foreach (Employee employee in employeeList)
{
int iDisplayCount = employee.EmployeeDisplayCollection.Count;
if (iDisplayCount > iMaxDisplayCount)
iMaxDisplayCount = iDisplayCount;
}
var employees = employeeList.GroupBy(p => p.EmployeeDisplayCollection.Count == iMaxDisplayCount).Select(g => g.ToList());
foreach(var employeeHighList in employees)
{
foreach (var employee in employeeHighList)
{
}
}
however for some reason, I am getting all the employees in the employeeHighList and not just the ones who have the highest display count.
I think the GroupBy is not correct, but don't know what's wrong with it.
Any help will be very much appreciated!
Thanks
var max = employeeList.Max(e=>e.EmployeeDisplayCollection.Count);
var maxEmp = employeeList.Where(e=>e.EmployeeDisplayCollection.Count == max)
.ToList()