A sequence of information about goods goodList of type Good and a sequence of prices of
goods in various stores storePriceList of type StorePrice are given. Each element of the
goodList sequence includes the Product SKU, Category, Country of origin fields.
Each element of the storePriceList sequence includes the Product SKU, Store Title,
Price fields.
For each country of origin get the number of stores offering goods manufactured in that
country, as well as the minimum price for goods from this country for all stores (CountryStat
values). If no product is found for a certain country that is presented in any store, then the
number of stores and the minimum price is assumed to be 0. Sort the list by country of origin.
Example:
goodList: new[]
{
new Good{Id = 1, Country = "Ukraine", Category = "Food"},
new Good{Id = 2, Country = "Ukraine", Category = "Food"},
new Good{Id = 3, Country = "Ukraine", Category = "Food"},
new Good{Id = 4, Country = "Ukraine", Category = "Food"},
new Good{Id = 5, Country = "Germany", Category = "Food"},
new Good{Id = 6, Country = "Germany", Category = "Food"},
new Good{Id = 7, Country = "Germany", Category = "Food"},
new Good{Id = 8, Country = "Germany", Category = "Food"},
new Good{Id = 9, Country = "Greece", Category = "Food"},
new Good{Id = 10, Country = "Greece", Category = "Food"},
new Good{Id = 11, Country = "Greece", Category = "Food"},
new Good{Id = 12, Country = "Italy", Category = "Food"},
new Good{Id = 13, Country = "Italy", Category = "Food"},
new Good{Id = 14, Country = "Italy", Category = "Food"},
new Good{Id = 15, Country = "Slovenia", Category = "Food"}
}
storePriceList: new[]
{
new StorePrice{GoodId = 1, Price = 1.25M, Shop = "shop1"},
new StorePrice{GoodId = 3, Price = 2.25M, Shop = "shop1"},
new StorePrice{GoodId = 5, Price = 4.25M, Shop = "shop1"},
new StorePrice{GoodId = 7, Price = 9.25M, Shop = "shop1"},
new StorePrice{GoodId = 9, Price = 11.25M, Shop = "shop1"},
new StorePrice{GoodId = 11, Price = 12.25M, Shop = "shop1"},
new StorePrice{GoodId = 13, Price = 13.25M, Shop = "shop1"},
new StorePrice{GoodId = 14, Price = 14.25M, Shop = "shop1"},
new StorePrice{GoodId = 5, Price = 11.25M, Shop = "shop2"},
new StorePrice{GoodId = 4, Price = 16.25M, Shop = "shop2"},
new StorePrice{GoodId = 3, Price = 18.25M, Shop = "shop2"},
new StorePrice{GoodId = 2, Price = 11.25M, Shop = "shop2"},
new StorePrice{GoodId = 1, Price = 1.50M, Shop = "shop2"},
new StorePrice{GoodId = 3, Price = 4.25M, Shop = "shop3"},
new StorePrice{GoodId = 7, Price = 3.25M, Shop = "shop3"},
new StorePrice{GoodId = 10, Price = 13.25M, Shop = "shop3"},
new StorePrice{GoodId = 14, Price = 14.25M, Shop = "shop3"},
new StorePrice{GoodId = 3, Price = 11.25M, Shop = "shop4"},
new StorePrice{GoodId = 2, Price = 14.25M, Shop = "shop4"},
new StorePrice{GoodId = 12, Price = 2.25M, Shop = "shop4"},
new StorePrice{GoodId = 6, Price = 5.25M, Shop = "shop4"},
new StorePrice{GoodId = 8, Price = 6.25M, Shop = "shop4"},
new StorePrice{GoodId = 10, Price = 11.25M, Shop = "shop4"},
new StorePrice{GoodId = 4, Price = 15.25M, Shop = "shop5"},
new StorePrice{GoodId = 7, Price = 18.25M, Shop = "shop5"},
new StorePrice{GoodId = 8, Price = 13.25M, Shop = "shop5"},
new StorePrice{GoodId = 12, Price = 14.25M, Shop = "shop5"},
new StorePrice{GoodId = 1, Price = 3.25M, Shop = "shop6"},
new StorePrice{GoodId = 3, Price = 2.25M, Shop = "shop6"},
new StorePrice{GoodId = 1, Price = 1.20M, Shop = "shop7"}
}
Expected Result:
expected: new[]
{
new CountryStat{Country = "Germany", MinPrice = 3.25M, StoresNumber = 5},
new CountryStat{Country = "Greece", MinPrice = 11.25M, StoresNumber = 3},
new CountryStat{Country = "Italy", MinPrice = 2.25M, StoresNumber = 4},
new CountryStat{Country = "Slovenia", MinPrice = 0.0M, StoresNumber = 0},
new CountryStat{Country = "Ukraine", MinPrice = 1.20M, StoresNumber = 7},
});
I had an idea to group storedPriceList by GoodId and then select min Price, but I have no idea what to do next.
goodList left join storePriceList by matching Id with GoodId
Group by Country
Select:
3.1. Get min value of Price
3.2. Remove Shop with null, distinct value and perform count
Order by Country
(
from a in goodList
join b in storePriceList on a.Id equals b.GoodId into ab
from b in ab.DefaultIfEmpty()
group new
{
Country = a.Country,
Price = b == null ? 0 : b.Price,
Shop = b == null ? null : b.Shop
} by a.Country into g
select new
{
Country = g.Key,
MinPrice = g.Min(x => x.Price),
StoresNumber = g.Where(x => x.Shop != null)
.Select(x => x.Shop)
.Distinct()
.Count()
}
)
.OrderBy(x => x.Country)
.ToList();
Demo # .NET Fiddle
var result = goodList
.Select(x => x.Country).Distinct()
.GroupJoin(
goodList.Join(storePriceList, good => good.Id, price => price.GoodId,
(good, goodsGroup) =>
new
{
Good = good,
Prices = goodsGroup
}), country => country, goods => goods.Good.Country,
(country, goods) => new
{
Country = country,
Goods = goods
})
.AsEnumerable()
.Select(x =>
new CountryStat
{
Country = x.Country,
MinPrice = x.Goods.Any() ? x.Goods.Select(y => y.Prices).Min(y => y.Price) : decimal.Zero,
StoresNumber = x.Goods.Any() ? x.Goods.Select(y => y.Prices).DistinctBy(y => y.Shop).Count() : 0
})
.OrderBy(x => x.Country)
.ToList();
you could Select countries in a list and remove repeated elements (hence a list of all countries). and from there you can easily divide the main list into list of list of goods per country (List<(string Country, List<prices>)>)
Related
I have a list of Receipts
IEnumerable<Receipt> Receipts =
new List<Receipt>()
{
new Receipt
{
Id = 1, CustomerId = 1, IsCheckedOut = false, OperationDate = new DateTime(2021, 1, 2),
ReceiptDetails = new List<ReceiptDetail>()
{
new ReceiptDetail { Id = 1, ProductId = 1, UnitPrice = 10, Product = ProductEntities.ElementAt(0), DiscountUnitPrice = 9, Quantity = 2, ReceiptId = 1 },
new ReceiptDetail { Id = 2, ProductId = 2, UnitPrice = 20, Product = ProductEntities.ElementAt(1), DiscountUnitPrice = 19, Quantity = 8, ReceiptId = 1},
new ReceiptDetail { Id = 3, ProductId = 3, UnitPrice = 25, Product = ProductEntities.ElementAt(2), DiscountUnitPrice = 24, Quantity = 1, ReceiptId = 1 },
}
},
new Receipt
{
Id = 2, CustomerId = 2, IsCheckedOut = false, OperationDate = new DateTime(2021, 1, 15),
ReceiptDetails = new List<ReceiptDetail>()
{
new ReceiptDetail { Id = 4, ProductId = 1, UnitPrice = 10, Product = ProductEntities.ElementAt(0), DiscountUnitPrice = 9, Quantity = 10, ReceiptId = 2 },
new ReceiptDetail { Id = 5, ProductId = 3, UnitPrice = 25, Product = ProductEntities.ElementAt(2), DiscountUnitPrice = 24, Quantity = 1, ReceiptId = 2 }
}
},
new Receipt
{
Id = 3, CustomerId = 1, IsCheckedOut = false, OperationDate = new DateTime(2021, 2, 15),
ReceiptDetails = new List<ReceiptDetail>()
{
new ReceiptDetail { Id = 6, ProductId = 1, UnitPrice = 10, Product = ProductEntities.ElementAt(0), DiscountUnitPrice = 9, Quantity = 10, ReceiptId = 3 },
new ReceiptDetail { Id = 7, ProductId = 2, UnitPrice = 25, Product = ProductEntities.ElementAt(1), DiscountUnitPrice = 24, Quantity = 1, ReceiptId = 3 }
}
}
};
I need to get the best selling(by quantity) products based on CustomerId
Here is my function
public IEnumerable<Product> GetMostSoldProductByCustomer(int customerId, int productCount)
{
var a = ReceiptEntities.Where(rd => rd.CustomerId == customerId)..SelectMany(x => x.ReceiptDetails);
var b = a.GroupBy(rd => rd.ProductId);
var c = b.Select(p => p.Select(y => y.Quantity).Sum());
}
I'm stuck on this, I have no idea how to connect b and c.
For better understanding, if customerId = 1 and productCount = 3. The function should return 3 products with Id = 1, 2, 3 accordingly in descending order by quantities
One note! The customer whose id = 1 has two receipts, that's why I'm calculating the sum of Quantity as there are the same products in different receipts
Try the following query:
public IEnumerable<int> GetMostSoldProductByCustomer(int customerId, int productCount)
{
var query =
from re in ReceiptEntities
where re.CustomerId == customerId
from rd in re.ReceiptDetails
group rd by rd.ProductId into g
select new
{
ProductId = g.Key,
TotalQuantity = g.Sum(x => x.Quantity)
} into s
orderby descending s.TotalQuantity
select s.ProductId;
return query;
}
I am trying to find a way to cut out repeated code in an application that center around LINQ select statements. Lets say we have existing table rows that need to be aggregated and grouped for different reporting requirements and all original data is just grouped by day and needs to be grouped by week / month and another property.
DataRow is an example object that needs to be grouped and converted into an object ReportTableRow (please note this is a much reduced object but the actual objects have far more properties and therefore become much more drawn out).
public class DataRow
{
public DateTime Date { get; set; }
public string AccountNumber { get; set; }
public string MachineNumber { get; set; }
public int TEST { get; set; }
}
public class ReportTableRow
{
public int WeekNumber { get; set; }
public int Month { get; set; }
public string AccountNumber{ get; set; }
public string MachineNumber { get; set; }
public int TEST { get; set; }
public string TEST_TRAFFICLIGHT { get; set; }
}
And we create a list of DataRows:
List<DataRow> reportTable = new List<DataRow>()
{
new DataRow()
{
Date = new DateTime(2021, 06, 14),
AccountNumber = "11111111",
MachineNumber = "00AB2021",
TEST = 2
},
new DataRow()
{
Date = new DateTime(2021, 06, 15),
AccountNumber = "11111111",
MachineNumber = "00AB2021",
TEST = 1
},
new DataRow()
{
Date = new DateTime(2021, 06, 15),
AccountNumber = "11111111",
MachineNumber = "00AB2021",
TEST = 6
},
new DataRow()
{
Date = new DateTime(2021, 06, 16),
AccountNumber = "11111111",
MachineNumber = "00AB2021",
TEST = 4
},
new DataRow()
{
Date = new DateTime(2021, 06, 17),
AccountNumber = "11111111",
MachineNumber = "00AB2021",
TEST = 2
},
new DataRow()
{
Date = new DateTime(2021, 06, 18),
AccountNumber = "11111111",
MachineNumber = "00AB2021",
TEST = 7
},
new DataRow()
{
Date = new DateTime(2021, 06, 19),
AccountNumber = "11111111",
MachineNumber = "00AB2021",
TEST = 2
},
new DataRow()
{
Date = new DateTime(2021, 06, 20),
AccountNumber = "11111111",
MachineNumber = "00AB2021",
TEST = 11
},
new DataRow()
{
Date = new DateTime(2021, 06, 14),
AccountNumber = "22222222",
MachineNumber = "11BC2021",
TEST = 2
},
new DataRow()
{
Date = new DateTime(2021, 06, 15),
AccountNumber = "22222222",
MachineNumber = "11BC2021",
TEST = 1
},
new DataRow()
{
Date = new DateTime(2021, 06, 15),
AccountNumber = "22222222",
MachineNumber = "11BC2021",
TEST = 6
},
new DataRow()
{
Date = new DateTime(2021, 06, 16),
AccountNumber = "22222222",
MachineNumber = "11BC2021",
TEST = 4
},
new DataRow()
{
Date = new DateTime(2021, 06, 17),
AccountNumber = "22222222",
MachineNumber = "11BC2021",
TEST = 2
},
new DataRow()
{
Date = new DateTime(2021, 06, 18),
AccountNumber = "22222222",
MachineNumber = "11BC2021",
TEST = 7
},
new DataRow()
{
Date = new DateTime(2021, 06, 19),
AccountNumber = "22222222",
MachineNumber = "11BC2021",
TEST = 2
},
new DataRow()
{
Date = new DateTime(2021, 06, 20),
AccountNumber = "22222222",
MachineNumber = "11BC2021",
TEST = 11
}
};
So if we either need the data grouped "BY WEEK" or "BY MONTH" then we need to actually return in the report the WeekNumber or Month number respectively and the grouping would look something like this where GetTrafficLight method returns a string value based on the value of the sum of TEST:
switch (aggregate.ToUpper())
{
case "BY WEEK":
reportTable = reportTable
.GroupBy(x => new { x.AccountNumber, WeekNumber = CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(x.Date, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday) })
.Select(x => new ReportTableRow
{
WeekNumber = x.Key.WeekNumber,
Month = x.Max(y => y.Date).Month,
MachineNumber = x.FirstOrDefault().MachineNumber,
TEST = x.Sum(y => y.TEST),
TEST_TRAFFICLIGHT = GetTrafficLight(x.Sum(y => y.TEST)
})
.ToList();
break;
case "BY MONTH":
reportTable = reportTable
.GroupBy(x => new { x.AccountNumber, x.Date.Month })
.Select(x => new ReportTableRow
{
WeekNumber = CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(x.Max(y => y.Date), CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday),
Month = x.Key.Month,
MachineNumber = x.FirstOrDefault().MachineNumber,
TEST = x.Sum(y => y.TEST),
TEST_TRAFFICLIGHT = GetTrafficLight(x.Sum(y => y.TEST)
})
.ToList();
break;
}
The question is, is there anyway to remove the "Select" code and pass it into either a method or object that would accept an anonymous grouping so that it can be reused multiple times. Changing the anonymous grouping to a compile time object that contains two properties means duplicates are then returned in the dataset, could be that finding a way to remove the duplicates in compile time grouped members might help to resolve?
Please note, the code has been created to pose this question.
This is optional, but the first thing I would do is put that "aggregate" into a boolean variable:
bool byWeek = aggregate.ToUpper() == "BY WEEK";
The next thing I would do is capture and tame that "GetWeekOfYear" logic:
int getFirstMonday (DateTime date) =>
CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(
date,
CalendarWeekRule.FirstFourDayWeek,
DayOfWeek.Monday
);
Doing these things makes it more feasible to put the conditional logic inside the GroupBy and Select methods, making it so that you don't have to do the whole thing twice:
List<ReportTableRow> results =
reportTable
.GroupBy(x => new {
x.AccountNumber,
TimeBin = byWeek ? getFirstMonday(x.Date): x.Date.Month
})
.Select(x => new ReportTableRow {
WeekNumber = byWeek ? x.Key.TimeBin : getFirstMonday(x.Max(y => y.Date)),
Month = byWeek ? x.Max(y => y.Date).Month : x.Key.TimeBin,
MachineNumber = x.FirstOrDefault().MachineNumber,
TEST = x.Sum(y => y.TEST),
TEST_TRAFFICLIGHT = GetTrafficLight(x.Sum(y => y.TEST))
})
.ToList();
I should note that your sample data makes it so that the results are the same regardless of 'aggregate' setting. But if you change it a bit, such as changing the days for some of the entries, you'll get different results in the aggregation. And at least for the changes I made my code repeats the behavior of your code when toggling 'aggregate'.
I need to print the people with average not greater than 4 for algebra.
For example, "SCHOOL: 131, NAME: BLA-BLA, AVERAGE: 3,5". Thats the thing i've tried but it gave me an exception "sequence contains no elements"
upd: "not greater than 4"
var result = students
.OrderBy(s => s.Surname)
.ThenBy(o => o.Initials)
.Select(n => new
{
Name = n.Surname + " " + n.Initials,
Class = n.Class,
Average = students
.Where(s => s.Subject == "Algebra" && n.Surname == s.Surname && n.Initials == s.Initials)
.Average(w => w.Mark)
});
var students = new[]
{
new {Subject = "Algebra", Surname = "Jopin", Initials = "S.S", Class = 5, Mark = 2},
new {Subject = "Algebra", Surname = "Jopin", Initials = "S.S", Class = 5, Mark = 2},
new {Subject = "Algebra", Surname = "Jopin", Initials = "S.S", Class = 5, Mark = 3},
new {Subject = "Geometry", Surname = "Jopin", Initials = "S.S", Class = 5, Mark = 5},
new {Subject = "C.S", Surname = "Jopin", Initials = "S.S", Class = 5, Mark = 5},
new {Subject = "C.S", Surname = "Jopin", Initials = "S.S", Class = 5, Mark = 5},
new {Subject = "Algebra", Surname = "Bloom", Initials = "Q.V", Class = 2, Mark = 5},
new {Subject = "Algebra", Surname = "Bloom", Initials = "Q.V", Class = 2, Mark = 5},
new {Subject = "Algebra", Surname = "Bloom", Initials = "Q.V", Class = 2, Mark = 5},
new {Subject = "Geometry", Surname = "Bloom", Initials = "Q.V", Class = 2, Mark = 5},
new {Subject = "C.S", Surname = "Bloom", Initials = "Q.V", Class = 2, Mark = 5},
new {Subject = "C.S", Surname = "Bloom", Initials = "Q.V", Class = 2, Mark = 5},
new {Subject = "Geometry", Surname = "Roflov", Initials = "E.Y", Class = 1, Mark = 2},
new {Subject = "C.S", Surname = "Roflov", Initials = "E.Y", Class = 1, Mark = 2},
new {Subject = "C.S", Surname = "Roflov", Initials = "E.Y", Class = 1, Mark = 2},
new {Subject = "Algebra", Surname = "Einstein", Initials = "B.H", Class = 4, Mark = 3},
new {Subject = "Algebra", Surname = "Einstein", Initials = "B.H", Class = 4, Mark = 4},
new {Subject = "Geometry", Surname = "Einstein", Initials = "B.H", Class = 4, Mark = 5}
};
The Average method can fail with InvalidOperationException if the sequence contains no elements.
From your example, it looks like at least for student "Roflow E.Y" there is no entry for "Algebra"
Something like this should do what you want.
var result = students
.Where(s => s.Subject == "Algebra")
.GroupBy(s => new{s.Surname, s.Initials, s.Class})
.Select(g => new{ Name = g.Key.Surname + g.Key.Initials, g.Key.Class, Average = g.Average(x => x.Mark)})
.Where(x => x.Average >= 4)
.OrderBy(x => x.Name);
(Edited)
This is my code with examples of the collections I am working with:
That's what I meant when I wrote that myProducts1 and myProducts1 are nested collections
List<MyProducts> myProducts1= {
new MyProducts{id = 1, Name = "product1", isExcl= true},
new MyProducts{id = 2, Name = "product2", isExcl= false},
new MyProducts{id = 3, Name = "product3", isExcl= true},
new MyProducts{id = 4, Name = "product4", isExcl= false}
}
List<MyProducts> myProducts2= {
new MyProducts{id = 5, Name = "product5", isExcl= true},
new MyProducts{id = 6, Name = "product6", isExcl= false}
}
IEnumerable<SelectedProductRequest> selectedProducts = {
new SelectedProductRequest {id = 1, Name = "product1", Price = 23},
new SelectedProductRequest {id = 1, Name = "product1", Price = 44},
new SelectedProductRequest {id = 2, Name = "product2", Price = 11},
new SelectedProductRequest {id = 6, Name = "product6", Price = 34},
}
List<CategoryProduct> productsWithCategories = {
{CategoryName= "Category1", categoryProduct = myProducts1 },
{CategoryName= "Category2", categoryProduct = myProducts2 }
}
Here is my first code:
IEnumerable<SelectedProductViewModel> products1 =
.GroupBy(categoryProduct => categoryProduct .CategoryName)
.Select(categoryProduct => new ProductCategoryViewModel(
categoryProduct .Key,
categoryProduct
.Select(product => new SelectedProductViewModel(
product.Name,
selectedProducts.FirstOrDefault(selectedProduct => selectedProduct.id== product.id)?.Price ?? 0,
product.IsExclusive))
.OrderByDescending(product => product.id)))
Here is my second code:
IEnumerable<SelectedProductViewModel> products2 =
.GroupBy(categoryProduct => categoryProduct .CategoryName)
.Select(categoryProduct => new ProductCategoryViewModel(
categoryProduct .Key,
categoryProduct
.Join(contractSelectedProducts, product => product.id, selected => selected.id, (product, selected) =>
new SelectedProductViewModel(
product.Name,
selected?.Price ?? 0,
product.IsExclusive))
The results I get with those pieces of code:
products1= {"Category1",{
new SelectedProductRequest {id = 1, Name = "product1", Price = 23, IsExclusive = true},
new SelectedProductRequest {id = 2, Name = "product2", Price = 11, IsExclusive = false},
new SelectedProductRequest {id = 3, Name = "product3", Price = 0, IsExclusive = true},
new SelectedProductRequest {id = 4, Name = "product4", Price = 0, IsExclusive = false}
},
"Category2", {new SelectedProductRequest {id = 5, Name = "product5", Price = 0, IsExclusive = true},
new SelectedProductRequest {id = 6, Name = "product6", Price = 34, IsExclusive = false}}
products2= {"Category1",{
new SelectedProductRequest {id = 1, Name = "product1", Price = 23, IsExclusive = true},
new SelectedProductRequest {id = 1, Name = "product1", Price = 44, IsExclusive = true},
new SelectedProductRequest {id = 2, Name = "product2", Price = 11, IsExclusive = false}
}},
"Category2", {new SelectedProductRequest {id = 6, Name = "product6", Price = 34, IsExclusive = false}
But the result I want to achieve is this:
products= {"Category1",{
new SelectedProductRequest {id = 1, Name = "product1", Price = 23, IsExclusive = true},
new SelectedProductRequest {id = 1, Name = "product1", Price = 44, IsExclusive = true},
new SelectedProductRequest {id = 2, Name = "product2", Price = 11, IsExclusive = false},
new SelectedProductRequest {id = 3, Name = "product3", Price = 0, IsExclusive = true},
new SelectedProductRequest {id = 4, Name = "product4", Price = 0, IsExclusive = false}
}},
"Category2",{
{new SelectedProductRequest {id = 5, Name = "product5", Price = 0, IsExclusive = true},
{new SelectedProductRequest {id = 6, Name = "product6", Price = 34, IsExclusive = false}
}
(edited code)
My question: How can I achieve this result without using products1 and products2? Or how can i do it in a better way?
updated as per comment
Solution 1
I changed the last Linq query by :
List<ProductCategory> mergedList = products1
// concat products2 with products1
.Concat(products2)
// group by category name
.GroupBy(x => x.CategoryName)
//dictionay(categoryName, list of SelectedProductRequests)
.ToDictionary(key => key, value => value.SelectMany(x => x.SelectedProductRequests)
.GroupBy(x => new { x.id, x.Name, x.Price, x.IsExclusive })
// take the first in grouped element
.Select(x => x.First())
//convert to SelectedProductRequest
.Select(x => new SelectedProductRequest { id = x.id, Name = x.Name, Price = x.Price, IsExclusive = x.IsExclusive })
.OrderBy(x => x.id)//order by id
.ToList())
.Select(x => new ProductCategory { CategoryName = x.Key.Key, SelectedProductRequests = x.Value })
.ToList();
Solution 2
if i understand your demand, you need to build productsWithCategories to get Expected result with one linq request, then check the following proposition by using GroupJoin instead Join :
IEnumerable<ProductCategoryViewModel> result = productsWithCategories
.Select(x => new ProductCategoryViewModel
{
CategoryName = x.CategoryName,
SelectedProductViewModels = x.categoryProduct
.GroupJoin(selectedProducts, prd => prd.id, sel => sel.id,
(prd, sel) => sel != null && sel.Any() ?
sel.Select(y =>
new SelectedProductViewModel
{
id = prd.id,
isExcl = prd.isExcl,
Name = prd.Name,
Price = y.Price
}).ToList() :
new List<SelectedProductViewModel>
{
new SelectedProductViewModel
{
id = prd.id,
isExcl = prd.isExcl,
Name = prd.Name,
Price = 0
}
})
.SelectMany(z => z)
.ToList()
});
i hope that will help you fix the issue
You can use Concat method to join arrays:
var selectedProductsMapped = selectedProducts.Select(s => new SelectedProductRequest
{
id = s.id,
Name = s.Name,
Price = s.Price,
isExclusive = myProducts.Where(p => p.id == s.id).FirstOrDefault().isExclusive
});
var exlcludedProducts = myProducts.Where(p => !selectedProducts.Any(sp => sp.id == p.id))
.Select(s => new SelectedProductRequest
{
id = s.id,
Name = s.Name,
Price = 0
});
var result = selectedProductsMapped.Concat(exlcludedProducts);
An example:
var selectedProducts = new List<SelectedProductRequest> {
new SelectedProductRequest {id = 1, Name = "product1", Price = 23},
new SelectedProductRequest {id = 1, Name = "product1", Price = 44},
new SelectedProductRequest {id = 2, Name = "product2", Price = 11}
};
var myProducts = new List<MyProducts> {
new MyProducts{id = 1, Name = "product1", isExclusive= true},
new MyProducts{id = 2, Name = "product2", isExclusive= false},
new MyProducts{id = 3, Name = "product3", isExclusive= true},
new MyProducts{id = 4, Name = "product4", isExclusive= false}
};
var selectedProductsMapped = selectedProducts.Select(s => new SelectedProductRequest
{
id = s.id,
Name = s.Name,
Price = s.Price,
isExclusive = myProducts.Where(p => p.id == s.id).FirstOrDefault().isExclusive
});
var exlcludedProducts = myProducts.Where(p => !selectedProducts.Any(sp => sp.id == p.id))
.Select(s => new SelectedProductRequest
{
id = s.id,
Name = s.Name,
Price = 0
});
var result = selectedProductsMapped.Concat(exlcludedProducts);
You can produce the set of products1 and products2 with Linq's Union(). You will need to implement SelectedProductRequest's GetHashCode().
products = products1.Union(products2);
Try it Online!
Add this to SelectedProductRequest:
public class SelectedProductRequest : IEquatable<SelectedProductRequest>
{
public int id {get;set;}
public string Name {get;set;}
public int Price {get;set;}
public bool IsExclusive {get;set;}
public bool Equals(SelectedProductRequest other) => other is null
&& this.id == other.id
&& this.Name == other.Name
&& this.Price == other.Price
&& this.IsExclusive == other.IsExclusive;
public override bool Equals(object obj) => Equals(obj as SelectedProductRequest);
public override int GetHashCode() => (id, Name, Price, IsExclusive).GetHashCode();
}
How could I select parking with id 1 and only the cars of year 200 in that park
var List<Parking> cityParkings = new List<Parking>
{
new Parking{ id = 1, carsInPark = new List<Car>{ new Car{ year = 2000}, new Car{ year = 2001} }},
new Parking{ id = 2, carsInPark = new List<Car>{ new Car{ year = 2000}, new Car{ year = 1999} }},
new Parking{ id = 3, carsInPark = new List<Car>{ new Car{ year = 2005}, new Car{ year = 2000} }},
}
expected result:
Parking { id = 1, carsInPark = List<Car>{ Car{ year = 2000} } }
select the existing parking instance of id 1 with existing cars instances, but only the cars of 2000's year.
Thanks ;)
Try
cityParkings.Where(p => p.id = 1)
.Select(pp => new Parking(){id = pp.id, carsInPark = pp.carsInPark.Where(c=>c.year == 2000).ToList()});