Remove list items within another list - c#

I think I'm halfway there in that I have managed to select all the items I want to remove. How do I actually remove them without resorting to a foreach loop?
List<LadderMatchItem> matchResults = (from p in ladder.Participants
from m in p.MatchResults
where m.Id == command.LadderMatchId
select m).ToList();
edit: Simplified Class structure
public class Ladder
{
public string Id { get; set; }
public IList<LadderParticipant> Participants { get; set; }
}
public class LadderParticipant
{
public string Id { get; set; }
public List<LadderMatchItem> MatchResults { get; set; }
}
public class LadderMatchItem
{
public string Id{ get; set; }
public LadderMatchResult Result { get; set; }
}

You can try is change your condition
ladder.Participants.ForEach(x => x.MatchResults.RemoveAll(ele => ele.Id == command.LadderMatchId));

Related

Find a particular element in List<> and fetch whole data of that row if element is found

I have a List<> which contains collection of objects after getting this list of BillSheetDetail I want to find that billWorkDetails[].details_classification =="xyz" and if it is found then fetch all the data of that particular array index of billWorksDetails[] and store it in other array to display.
How can I do this? I am new to C#
public class BillSheetDetail
{
public DateTime creation_date { get; set; }
public string customer_name { get; set; }
public string subject { get; set; }
public decimal tax_rate { get; set; }
public int total_amount { get; set; }
public string special_instruction { get; set; }
public string comment { get; set; }
public List<BillWorkDetail> billWorkDetails { get; set; }
}
[Serializable]
public class BillWorkDetail
{
public string product_name { get; set; }
public decimal quantity { get; set; }
public string unit { get; set; }
public int unit_cost { get; set; }
public int amount { get; set; }
public string remarks { get; set; }
public int row_no { get; set; }
public string details_classifiction { get; set; }
}
You have to combine Enumerable.Where and Any.
List<BillWorkDetail>[] matchingSheetDetails = billSheetDetailList
.Where(sd => sd.billWorkDetails.Any(d => d.details_classifiction == "xyz"))
.Select(sd => sd.billWorkDetails)
.ToArray();
This creates an array of all matching lists. Since your question is unclear, if you actually only want an array of the matching BillWorkDetail objects:
BillWorkDetail[] matchingBillWorkDetails = billSheetDetailList
.SelectMany(sd => sd.billWorkDetails.Where(d => d.details_classifiction == "xyz"))
.ToArray();
SelectMany selects all matching BillWorkDetail out of the List<BillSheetDetail>. Note that both approaches lose the reference to the BillSheetDetail instance from where it came from.
The solution is using the Where clause:
mySheetDetail.billWorkDetails.Where(x => x.details_classification == "xyz").ToList();
Here is a demonstration of the code that is working well: http://ideone.com/s2cUaR
Try this linq method
List<BillWorkDetail> myBillWorkDetails = new Lis<BillWorkDetail>();
myBillWorkDetails = myBillSheetDetail.billWorkDetails.Where(b => b.classifiction == "xyz").ToList();
This code retrieve all BillWorkDetail with classification xyz.

How do you convert several nested loops into lambda or linq when you have a complex object structure?

I am running into trouble when trying to convert my multiple nested loops into a lambda or linq expression. I think I am having a hard time understanding how to properly access the properties when using the .All or .Contains methods. In any case, help is greatly appreciated. (I have read several other posts on this subject but am still struggling to make it work.)
Here are what the classes look like:
public class RecipeSearch
{
public List<Recipe> Recipe { get; set; }
public List<Meal> MealSettings { get; set; }
public List<Ingredient> MainIngredient { get; set; }
}
public class Meal
{
public int Id { get; set; }
public bool Value { get; set; }
public string DisplayName { get; set; }
}
public class MainIngredient
{
public int Id { get; set; }
public bool Value { get; set; }
public string DisplayName { get; set; }
}
Here's the nested loop:
IEnumerable<Recipe> recipeList = dbContext.Recipes
.OrderBy(r => r.name)
.Where(r => r.name.Contains(name) || string.IsNullOrEmpty(name))
.ToList();
//Model object is of type RecipeSearch
IEnumerable<Meal> selectedMeals = model.MealSettings.Where(x => x.Value == true);
IEnumerable<MainIngredient> selectedIngredients = model.MainIngredient.Where(x => x.Value == true);
foreach (var selected in recipeList) //loop through the master list
{
foreach (var item in selectedMeals) //loop through selected meal categories
{
if (selected.mealCategoryId == item.Id) //passed the meal category check (i.e. it exists)
{
foreach (var ingredient in selectedIngredients) // selected master ingredients
{
if (selected.Ingredients.Any(x => x.SubCategory.mainCategoryid == ingredient.Id))
{
recipe.Recipe.Add(selected);
break;
}
}
}
}
}
I suppose it should be noted that the loop works completely as expected. I just think that it lambda/linq is more clean to read.
EDIT: Here are the other objects:
public partial class Recipe
{
public Recipe()
{
Directions = new HashSet<Direction>();
Images = new HashSet<Image>();
Ingredients = new HashSet<Ingredient>();
Nutritions = new HashSet<Nutrition>();
Ratings = new HashSet<Rating>();
}
public int recipeId { get; set; }
//Removed other properties that are not relevant
public virtual ICollection<Ingredient> Ingredients { get; set; }
public virtual MealCategory MealCategory { get; set; }
public virtual RecipeStatus RecipeStatus { get; set; }
}
public partial class Ingredient
{
public int ingredientId { get; set; }
public int? recipeId { get; set; }
public int? subCategoryId { get; set; }
public int measurementId { get; set; }
public int amount { get; set; }
public virtual Recipe Recipe { get; set; }
public virtual SubCategory SubCategory { get; set; }
public virtual Measurement Measurement { get; set; }
}
public partial class SubCategory
{
public SubCategory()
{
Ingredients = new HashSet<Ingredient>();
}
public int subCategoryId { get; set; }
[Required]
[StringLength(255)]
public string name { get; set; }
public int? mainCategoryid { get; set; }
public virtual ICollection<Ingredient> Ingredients { get; set; }
public virtual Maincategory Maincategory { get; set; }
}
Would this work?
var query = from selected in receipeList
join item in selectedMeals on selected.MealCategoryId equals item.Id
where selected.Ingredients.Select(x => x.SubCategory.mainCategoryid.Value)
.Intersect(selectedIngredients.Select(s => s.Id)).Count() > 0
select selected;
foreach(var sel in query)
recipe.Recipe.Add(sel);
I can't see where you are getting recipe.Recipe from though.
Basically in order to help you translate that into linq and adjust as you want:
This:
foreach (var selected in recipeList) //loop through the master list
{
foreach (var item in selectedMeals) //loop through selected meal categories
{
if (selected.mealCategoryId == item.Id) //passed the meal category check (i.e. it exists)
{
}
}
}
Translates into join like so:
from selected in receipeList
join item in selectedMeals on selected.MealCategoryId equals item.Id
Also, these lines:
if (selected.Ingredients.Any(x => x.SubCategory.mainCategoryid == ingredient.Id))
{
recipe.Recipe.Add(selected);
break;
}
Can be translated into:
where selected.Ingredients.Select(x => x.SubCategory.mainCategoryid.Value)
.Intersect(selectedIngredients.Select(s => s.Id)).Count() > 0
select selected;
//and then
foreach(var sel in query)
recipe.Recipe.Add(sel);
Notice the following part,
IEnumerable<Recipe> recipeList = dbContext.Recipes
.OrderBy(r => r.name)
.Where(r => r.name.Contains(name) || string.IsNullOrEmpty(name))
.ToList();
2 things smell here:
First, you should swap the or-condition to check String.IsNullOrEmpty first, and
second put the where before the orderby to reduce items that need to be ordered.
IEnumerable<Recipe> recipeList = dbContext.Recipes
.Where(r => string.IsNullOrEmpty(name) || r.name.Contains(name))
.OrderBy(r => r.name)
.ToList();
Depending on the ItemCount this might give you quite some "boost".

Find object with in class using LINQ

I want to return the item that has the profile ID I send. So in order to do this I will need to loop through all of the Items -> WebProproperties -> profile. The Class structure is at the end of the question.
I would rather use LINQ than create a nested foreach. I have been trying to get this to work for more than an hour now. I am stuck.
My first idea was to simply use where. But that doesn't work because you need to have something on the other side that needs to equal.
this.Accounts.items.Where(a => a.webProperties.Where(b => b.profiles.Where(c => c.id == pSearchString)) ).FirstOrDefault();
My second idea was to try using Exists which I don't have much experience with:
Item test = from item in this.Accounts.items.Exists(a => a.webProperties.Exists(b => b.profiles.Exists(c => c.id == pSearchString))) select item;
This doesn't work either:
Could not find an implementation of query pattern for source type 'Bool'
public RootObject Accounts {get; set;}
public class RootObject
{
public string kind { get; set; }
public string username { get; set; }
public int totalResults { get; set; }
public int startIndex { get; set; }
public int itemsPerPage { get; set; }
public List<Item> items { get; set; }
}
public class Profile
{
public string kind { get; set; }
public string id { get; set; }
public string name { get; set; }
public string type { get; set; }
}
public class WebProperty
{
public string kind { get; set; }
public string id { get; set; }
public string name { get; set; }
public string internalWebPropertyId { get; set; }
public string level { get; set; }
public string websiteUrl { get; set; }
public List<Profile> profiles { get; set; }
}
public class Item
{
public string id { get; set; }
public string kind { get; set; }
public string name { get; set; }
public List<WebProperty> webProperties { get; set; }
}
You can use Any() to determine existence. Also, note that many of the extension methods have overloads which take a predicate, including FirstOrDefault():
this.Accounts.items.FirstOrDefault(a => a.webProperties
.Any(b => b.profiles
.Any(c => c.id == pSearchString)));
You are looking for the .Any() operation I think. This will return true/false for whether there are any items matching your query.
For example:
if (this.Accounts.Items.Any(i=>i.webProperties.Any(wp=>wp.profiles.Any(p=>p.id == MySearchId)));
EDIT: You have full answer (was posted while I was composing mine) and as pointed out in comments my answer isn't actually returning your found item, just letting you know whether there is one. You can rework the first .Any to be a .FirstOrDefault to get that match.
E.g.
var result = this.Accounts.Items.FirstOrDefault(i=>i.webProperties.Any(wp=>wp.profiles.Any(p=>p.id == MySearchId)))
You can use the below mentioned code.
var abc = rr.items.Where(p => p.webProperties.Any(c => c.profiles.Any(d => d.id == "1"))).FirstOrDefault();
Just for your reference, your class should look like:
public class RootObject
{
public string kind { get; set; }
public string username { get; set; }
public int totalResults { get; set; }
public int startIndex { get; set; }
public int itemsPerPage { get; set; }
private List<Item> _items=new List<Item>();
public List<Item> items
{
get { return _items; }
set { _items = value; }
}
}

A better way to retrieve EF data and collections

So I have a model that contains a list of models which contains items, and so on, like this:
public partial class CART
{
public CART()
{
//this.CART_DETAIL = new HashSet<CART_DETAIL>();
this.CART_DETAIL = new List<CART_DETAIL>();
}
public int CART_IDE { get; set; }
public int CART_COUNT { get; set; }
public string SHOPPING_CART_IDE { get; set; }
public virtual IList<CART_DETAIL> CART_DETAIL { get; set; }
}
public partial class CART_DETAIL
{
public int CART_DETAIL_IDE { get; set; }
public int CART_IDE { get; set; }
public int CART_DETAIL_COUNT { get; set; }
public Nullable<int> PACK_IDE { get; set; }
public Nullable<int> BACKSTORE_INVENTORY_IDE { get; set; }
public virtual CART CART { get; set; }
public virtual PACK PACK { get; set; }
public virtual BACKSTORE_INVENTORY BACKSTORE_INVENTORY { get; set; }
}
public partial class BACKSTORE_INVENTORY
{
public BACKSTORE_INVENTORY()
{
this.CART_DETAIL = new HashSet<CART_DETAIL>();
this.ORDER_DETAIL = new HashSet<ORDER_DETAIL>();
}
public int BACKSTORE_INVENTORY_IDE { get; set; }
public int INVENT_IDE { get; set; }
public int STORE_IDE { get; set; }
public decimal BACKSTORE_INVENTORY_PRICE { get; set; }
public int BACKSTORE_STOCK_QTY { get; set; }
public decimal BACKSTORE_DISCOUNT { get; set; }
public decimal BACKSTORE_SELLING_PRICE { get; set; }
public virtual INVENTORY INVENTORY { get; set; }
public virtual STORE STORE { get; set; }
public virtual ICollection<CART_DETAIL> CART_DETAIL { get; set; }
public virtual ICollection<ORDER_DETAIL> ORDER_DETAIL { get; set; }
}
When I open a connection and consult the data, everything's fine, but if I retrive the whole data in a view, for example, unless I modify the Hashset to a List and then proceed like this:
CART cart =
db.CART.FirstOrDefault(_item => _item.SHOPPING_CART_IDE == mShoppingCartID && _item.CART_ACTIVE_INDICATOR);
if (cart != null)
{
cart.CART_EXP_TIME = DateTime.Now.AddMinutes(90);
cart.USER_SESSION_IDE = UserSessionManager.GetUserSession().mUserSessionID;
cart.CART_DETAIL = cart.CART_DETAIL.ToList();
foreach (var cartDetail in cart.CART_DETAIL)
{
if(cartDetail.BACKSTORE_INVENTORY_IDE != null)
{
cartDetail.BACKSTORE_INVENTORY =
db.BACKSTORE_INVENTORY.First(_item => _item.BACKSTORE_INVENTORY_IDE == cartDetail.BACKSTORE_INVENTORY_IDE);
cartDetail.BACKSTORE_INVENTORY.INVENTORY =
db.INVENTORY.Find(cartDetail.BACKSTORE_INVENTORY.INVENT_IDE);
cartDetail.BACKSTORE_INVENTORY.INVENTORY.CARD =
db.CARD.Find(cartDetail.BACKSTORE_INVENTORY.INVENTORY.CARD_IDE);
}
else
{
cartDetail.PACK = db.PACK.First(_item => _item.PACK_IDE == cartDetail.PACK_IDE);
}
}
db.SaveChanges();
}
I get the following error: CS0021: Cannot apply indexing with [] to an expression of type 'System.Collections.Generic.ICollection<MyApp.Models.DAL.Entities.CART_DETAIL>' which I understand is because the ICollection does not afford indexing, and then I get The ObjectContext instance has been disposed and can no longer be used for operations that require a connection. for items that I forgot to retrive.
So my question: what makes this happen? Is there a way to retrieve all the data at once without having to get all specific items separately? A better way to do things?
What are you trying to achieve form the above code?
I am struggling to follow what your end goal is but would something along these lines be what you are looking for:
public List<Cart> GetAllInCart()
{
return db.CART.Where(a => a.Cart_IDE == CartIDE)
.Include(x => x.Cart_Detail)
.Include(x => x.Cart_Detail.Pack)
.Include(x => x.Cart_Detail.Backstore_Inventory)
.ToList()
}
I hope this helps :)

Filtering LINQ child collection EF

Im having some problems trying to do this filtering and im sure it can be done better than what im doing. I will show my classes and how im solving it but i was wondering if I could use Linq to filter this. My Classes:
public class Section
{
public int Id { get; set; }
public string Name { get; set; }
public int Order { get; set; }
public virtual List<FeatureType> Features { get; set; }
}
public class ItemType
{
public int Id { get; set; }
public string Name { get; set; }
public virtual List<FeatureType> FeatureTypes { get; set; }
public override string ToString()
{
return Name;
}
}
public class FeatureType
{
public int Id { get; set; }
public string Name { get; set; }
public Section Section { get; set; }
public virtual List<ItemType> ItemTypes { set; get; }
}
I'm trying to get all Sections, and filter Features by an ItemTypeID, so only the FeatureTypes of that ItemTypes are listed. What Im doing now its just getting all sections, and just do a for and just add the ones that work for me in other:
public ItemTypeFeatureViewModel(int myItemTypeId, IUnitOfWork myUnitOfWork)
{
ItemTypeId = myItemTypeId;
unitOfWork = myUnitOfWork;
Sections = unitOfWork.SectionRepository.Get(includeProperties: "Features")
.ToList();
foreach (var item in Sections)
{
var x = new List<FeatureType>();
foreach (var feature in item.Features)
{
foreach (var itemType in feature.ItemTypes)
{
if (itemType.Id == ItemTypeId)
{
x.Add(feature);
break;
}
}
}
item.Features = x;
}
}
Can i improve this and avoid all this foreach?
You can't filter out included collection on server side, but you can replace two inner loops with:
item.Features = item.Features
.Where(f => f.ItemTypes.Any(i => i.Id == ItemTypeId))
.ToList();
That will select only those features which have at least one item type with id you provided.
Try the following:
Sections
.ForEach(x => x.Features = x.Features.Where(y => y.Any(z => z.Id == ItemTypeId))
.ToList());

Categories

Resources