How to find if item in one Observable Collection? - c#

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;
}

Related

Getting a list of objects of 2 different lists

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)

Finding objects in a collection that have any string from a list in a subcollection

Ok, this one has me stumped.
I have a collection of objects called Interviews. An Interview has a collection of Notes in it. A Note has string (nvarchar(max) on the database) property called NoteText.
I have a List called keywords.
What I need to do is find all interviews that have a Note that has any of the keywords within its NoteText property.
I have this so far:
var interviewQuery =
from i in dbContext.Interviews //dbContext was created with Telerik OpenAccess
.Include(n => n.Notes)
.Where(i => i.Notes.Any(n => keywords.Contains(n.NoteText) ))
orderby i.WhenCreated descending
select i;
I don't get an error, I just don't get any results either.
I'm pretty poor at linq, but this can be easily done with a loop instead.
var matchinginterviews = new List<Interview>();
foreach (var inter in MyInterviewEnumerable)
{
foreach (var note in inter.NoteCollection)
{
foreach (string keyword in keywordList)
{
if (note.NoteText.IndexOf(keyword) != -1)
{
matchinginterviews.Add(inter);
}
}
}
}
What's causing the empty results is that you're looking for any keyword values that contain the entire content of any of the notes.
We made an extension method ContainsAny:
public static bool ContainsAny(this string s, IEnumerable<string> possibleContained)
{
foreach (string p in possibleContained)
{
if (s == p) return true;
if (s == null) continue;
if (s.Contains(p)) return true;
}
return false;
}
Then you could do something similar to where you started:
var results = dbContext.Interviews.Where(i => i.Notes.Any(n => n.NoteText.ContainsAny(keywords)));

Nested Object from DataTable

I feel like I am way off track here. I have been banging my head against my keyboard and I do not feel like I am any closer to a solution. Guidance would be much appreciated.
Models.Content contains a SubContent property that is of type List<Models.Content>. The nesting could be infinite and should be recursive. I feel like this should be able to be done with a few lines of LINQ and while or something to that affect. I have created a mess.
private static List<Models.Content> GetAllContentFromDataSet(DataSet ds)
{
var content = new List<Models.Content>();
var contentList = (from DataRow row in ds.Tables[0].Rows
select new Models.Content
{
Id = Convert.ToInt32(row["Id"]),
ParentContentId = Convert.ToInt32(row["ParentContentId"]),
c3 = Convert.ToString(row["c3"]),
c4 = Convert.ToString(row["c4"]),
c5 = Convert.ToString(row["c5"])
}).ToList();
content.AddRange(NestContent(contentList));
return content;
}
private static IEnumerable<Models.Content> NestContent(List<Models.Content> content)
{
var toBeRemoved = new List<Models.Content>();
foreach (var c in content)
{
var parent = content.FirstOrDefault(p => p.Id == c.ParentContentId);
if (parent == null) continue;
parent.SubContent.Add(c);
toBeRemoved.Add(c);
}
foreach (var c in toBeRemoved)
{
content.Remove(c);
}
return content;
}
Here's an example of what I would do:
// Create a list of all items without children.
var things = table.AsEnumerable()
.Select(row => new Thing
{
Id = row.Field<int>("Id"),
ParentId = row.Field<int>("ParentId")
})
.ToList();
// Add children to each item.
things.ForEach(t1 => t1.Children = things.Where(t2 => t2.ParentId == t1.Id).ToList());
// Create a list of items that don't have a parent..
things = things.Where(t => t.ParentId == 0).ToList();
I agree, I think you could build your model hierarchy with fewer lines of code, thus, making your code easier to maintain and read. I'd actually do this in two steps...
Parsing the root "content" first (those with ParentContentId == null...I guess)...this can be done in one line of code with LINQ
Then iterate through all child content rows (those with a ParentContentId specified) and "attach" them to the parent content (if exists)
Let me know if you got the idea or if you need an example

Update a List<T> witha SubList<T> performance (LINQ or Not)

I have a list which can have ~200'000 items. I need to update a fixed number of fields for, for instance 150 item, using a sub-list. This is the code I am using right now:
listItem: 200'000 item List - subListItem: 150 item List (updated)
listItem.Select(item =>
{
if (subListItem.Exists(x => x.ID == item.ID))
{
var currentItem = subListItem.Single(x => x.ID == item.ID);
item.FIELD_1 = currentItem.FIELD_1;
item.FIELD_2 = currentItem.FIELD_2;
item.FIELD_3 = currentItem.FIELD_3;
item.FIELD_4 = currentItem.FIELD_4;
}
return item;
}).ToList();
This is working good, but performance are really poor. Have you any advice ?
UPDATED SOLUTION:
dictItem = listItem.ToDictionary(x => x.ID);
foreach (Item updatedItem in subListItem)
{
Item originalItem = dictItem[updatedItem.ID];
originalItem.FIELD_1 = updatedItem.FIELD_1;
originalItem.FIELD_2 = updatedItem.FIELD_2;
originalItem.FIELD_3 = updatedItem.FIELD_3;
originalItem.FIELD_4 = updatedItem.FIELD_4;
dictItem[updatedItem.ID] = originalItem;
}
Make use of a dictionary to make the item lookup much quicker, i.e.
var subListItemsById = subListItems.ToDictionary(x => x.ID);
foreach(var item in listItem)
{
SubListItem subListItem;
if(subListItemsById.TryGetValue(item.ID, out subListItem))
{
item.FIELD_1 = subListItem.FIELD_1;
item.FIELD_2 = subListItem.FIELD_2;
item.FIELD_3 = subListItem.FIELD_3;
item.FIELD_4 = subListItem.FIELD_4;
}
}
Your original listItem will contain the modified objects. This will only work if the items contained in listItem are reference types. If they are mutable structs you will need to do similar to your example:
var subListItemsById = subListItems.ToDictionary(x => x.ID);
var modifiedItems = listItem.Select(item =>
{
SubListItem subListItem;
if(subListItemsById.TryGetValue(item.ID, out subListItem))
{
item.FIELD_1 = subListItem.FIELD_1;
item.FIELD_2 = subListItem.FIELD_2;
item.FIELD_3 = subListItem.FIELD_3;
item.FIELD_4 = subListItem.FIELD_4;
}
return item;
}).ToList();
If you need better performance, you need to use a container that is optimized for lookups. For example a Dictionary using your ID as key.
You can speed it up a lot by creating a dictionary as stated. However you can also keep the original list if you don't have to create a copy, reducing memory footprint.
var subItemLookup = subItems.ToDictionary(i => i.Id);
foreach (var item in items)
{
SubItem subItem;
if (subItemLookup.TryGetValue(item.Id, out subItem))
{
item.Field1 = subItem.Field1;
//etc.
}
}

Removing duplicates from a sorted list c#

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();

Categories