Below is my class structure:
public class TopLevel
{
public int Id { get; set; }
public List<ChildLevelList> ChildLevelList { get; set; }
}
public class ChildLevelList
{
public int Id { get; set; }
public List<ChildLevelList1> ChildLevelList1 { get; set; }
}
public class ChildLevelList1
{
public int Id { get; set; }
}
Now i am trying to get that ChildLevelList1 whose length is highest among all other ChildLevelList1 for each TopLevel records.If found then return that list of ChildListLevel1 for that Top level record
For eg: suppose i have records like below:
TopLevel[0]: ChildLevelList1 (Length =3)
TopLevel[1]: ChildLevelList1 (Length =4)
TopLevel[2]: ChildLevelList1 (Length =8) //get this list
TopLevel[3]: ChildLevelList1 (Length =2)
So I would like to get ChildLevelList for TopLevel 2 i.e from third position like below:
Output:[2]: ChildLevelList1 (Length =8)
I am trying to get in below variable:
var childLevelList1 // trying to get in this varaible
This is how I am trying:
for (int i = 0; i < List.Count(); i++)
{
//Sorry but not getting how to do this.
}
First of all I choose some better names to avoid confusion
public class TopLevel
{
public int Id { get; set; }
public List<ChildLevel> ChildLevelList { get; set; }
}
public class ChildLevel // was ChildLevelList
{
public int Id { get; set; }
public List<ChildLevel1> ChildLevelList1 { get; set; }
}
public class ChildLevel1 // was ChildLevel1List
{
public int Id { get; set; }
}
And to get the List with the highest length
public List<ChildLevel1> GetBiggestChildLevel1List( IEnumerable<TopLevel> source )
{
return source
.SelectMany( t => t.ChildLevelList ) // IEnumerable<ChildLevel>
.Select( c1 => c1.ChildLevelList1 ) // IEnumerable<List<ChildLevel1>>
.OrderByDescending( c2l => c2l.Count ) // IEnumerable<List<ChildLevel1>>
.FirstOrDefault();
}
You are going down two levels from TopLevel, therefore you can try with the following LINQ query:
var result = List.OrderByDescending(x => x.ChildLevelList.Select(y => y.ChildLevelList1.Count())).First();
Related
I have these two classes
enum CustomerType {
CitizenBank = 0,
Wellsfargo = 1
}
public abstarct class CustomerDto {
int customerId {
get;
set;
}
string customerName {
get;
set;
}
string CustometAddress {
get;
set;
}
int CustomerTypeId {
get;
set;
}
}
public CitizenBank: CustomerDto {}
public Wellsfargo: CustomerDto {}
Public Class CustomerEntity {
int customerId {
get;
set;
}
string customerName {
get;
set;
}
string CustometAddress {
get;
set;
}
int CustomerTypeId {
get;
set;
}
}
I wrote a class to convert from entity to DTO
public class EntityModelToModel {
///Method to convert
public CustomerDto ToDto(CustomerEntity customerEntity) {
/// returns type customerDto based on customertypeid
switch (CustomerType) {
case Wellsfargo
return New Wellsfargo()
case citizen
return new citizen() //calls method that converts from customer Entity to citizen
}
}
I have method to check if my types match
public bool CanExecute(CustomerEntity customerEntity) {
foreach(var customerType in Enum.GetValues(typeof(Enums.customerType) if (customerEntity.CustomerType == customerType)
return true
else
false
}
}
Now my calling code I have array of CustomerEntity[] which have two items of customerid for wellsfargo and citizens. I want to do this
var res = CustomerEntity[].where(x => EntityModelToModel.CanExecute(x).Select(x => EntityModelToModel.ToDto(x))
My problem is:
If my array has two items this only checks the first items and returns.
What I want is it should check for two items and return them.
I think that you should change your CanExecute method like this:
public static class EntityModelToModel
{
// ...
public static bool CanExecute(CustomerEntity customerEntity)
{
foreach (var customerType in Enum.GetValues(typeof(CustomerType)))
{
if (customerEntity.CustomerTypeId == (int)customerType)
{
return true;
}
}
return false;
}
}
Because your method break execution flow after first check.
My Main problem is : if i add "N" group to company and check it in the last , i see all of "Man"s arrange into all of groups like together ?
i this my problem is in the definition of class or references .
This is my code :
public class Man
{
public int Code { get; set; }
public string Name { get; set; }
public int Priority { get; set; }
public int Stoptime { get; set; }
public Boolean Lunch { get; set; }
public DateTime Arrival { get; set; }
public DateTime Departure { get; set; }
public int LunchTime { get; set; }
}
public class Group
{
public List<Man> People { get; set; }
public double Speed { get; set; }
public double Rate { get; set; }
public double Surcharge { get; set; }
public double TotalRate { get; set; }
}
public class Company
{
public List<Group> Groups { get; set; }
public Group BestGroup { get; set; }
public double Rate { get; set; }
public double Surcharge { get; set; }
public double FullRate { get; set; }
}
private List<Man> ShufflePosts(List<Man> ShufflePeoples)
{
List<Man> Temp = ShufflePeoples;
List<Man> Commixed = new List<Man>();
Random rand = new Random();
do
{
int shf = rand.Next(0, Temp.Count);
Commixed.Add(Temp[shf]);
Temp.RemoveAt(shf);
} while (Temp.Count > 1);
Commixed.Add(Temp[0]);
return Commixed;
}
public void CAStart(List<Man> Peoples)
{
var _Race = new Company();
_Race.Groups = new List<Group>();
for (int i = 0; i < 5; i++)
{
var Gr = new Group();
Gr.People = ShufflePosts(Peoples);
_Race.Groups.Add(Gr);
}
}
In the code Commixed.Add(Temp[0]); VS show me error index out of range.
I check the variable and see below data:
ShufflePeoples.Count = 0, Temp.Count = 0, Commixed.Count = 1
Why this happens ?
Where is my problem ?
Why you get the error:
Your do while loop runs until Temp.Count > 1 isn't true - which will happen when you removed all items from it with line Temp.RemoveAt(shf);.
Then you try accessing Temp[0] (the first item) but temp is empty and you get an index out of range error.
Try to change your loop's condition and avoid accessing a specific position in the collection without checking that that position exists. Or better still use a simple while instead and then you won't need to specially address the last item in Temp
A nice solution for shuffling:
var suffled = ShufflePeoples.OrderBy(item => Guid.NewGuid());
Change your loop to avoid index out of range error:
while (Temp.Count > 0)
{
int shf = rand.Next(0, Temp.Count);
Commixed.Add(Temp[shf]);
Temp.RemoveAt(shf);
};
When you remove item from Temp, you also remove it from ShufflePeoples because you refer Temp = ShufflePeoples, to avoid it, just make new list then copy items from ShufflePeoples to Temp.
You remove all Temp items in do-while loop, so when you try to access Temp[0] after loop, it will give you index out of range.
For the first time, ShufflePosts method will remove all the contents of the ShufflePeoples.
Therefore the second time you run ShufflePosts method, ShufflePeoples or Temp' is basically empty, which means if you try to accessTemp[0]`, it will give you index out of range Exception.
My 2 cents:
Avoid assigning Temp = ShufflePeoples, instead do Copy Constructor Temp = new List<Man>(ShufflePeoples), to make sure that you do not adjust the parameter accidentally
Always check your initial condition of your parameter argument.
I have a Silverlight application and a gridview bound from a domaindatasource control, and i am querying a view from domain data source using two parameters, but from the result, i need to sum 4 columns, grouping by the others.
My metadata class:
internal sealed class vwAplicacoesMetadata
{
// Metadata classes are not meant to be instantiated.
private vwAplicacoesMetadata()
{
}
public Nullable<int> CodInternoCliente { get; set; }
public Nullable<int> CodTipoOper { get; set; }
public string CPFCNPJCliente { get { return this.CPFCNPJCliente; } set { String.Format("{0,-14}", value); } }
public string TipoClientePFPJ { get; set; }
public string NomeCliente { get; set; }
public DateTime DataOper { get; set; }
public decimal LCQtde { get; set; }
public decimal LCValor { get; set; }
public decimal LDQtde { get; set; }
public decimal LDValor { get; set; }
}
}
And the IQueryable function i need to use the groupby and sum expressions:
public IQueryable<vwAplicacoes> GetVwAplicacoesPorData(DateTime pstrDataInicio, DateTime pstrDataFinal)
{
return this.ObjectContext.vwAplicacoes.Where(d => d.DataOper > pstrDataInicio && d.DataOper < pstrDataFinal)
}
Its working, and now i need to group by CPFCNPJCliente, NomeCliente, TipoClientePFPJ, CodInternoCliente and CodTipoOper, and sum the fields LCValor, LCQtde, LDValor, LDQtde.
Any suggestion?
Try this:
return this.ObjectContext.vwAplicacoes
.Where(d => d.DataOper > pstrDataInicio && d.DataOper < pstrDataFinal)
.GroupBy(x => new {x.CPFCNPJCliente,x.NomeCliente,x.TipoClientePFPJ,x.CodInternoCliente,x.CodTipoOper})
.Select(k => new {key = k.Key,
totalLCValor = k.Sum(x=>x.LCValor),
totalLCQtde = k.Sum(x=>x.LCQtde),
totalLDValor = k.Sum(x=>x.LDValor),
totalLDQtde = k.Sum(x=>x.LDQtde)})
I have two models:
public class CarRent
{
public string CarName { get; set; }
public string SystemId { get; set; }
public DateTime RentEndDate { get; set; }
}
public class CarPurchase
{
public string CarName { get; set; }
public string SystemId { get; set; }
public decimal Mileage { get; set; }
}
I need to combine them into one list, group by CarName and then inside each group I need to sort models initially by SystemId, but then if models have the same SystemId - I need to sort CarRent models by RentEndDate and CarPurchase by Mileage.
What I have tried:
I defined an interface:
public interface ICarPurchaseOrdered
{
string CarName { get; }
string SystemId { get; }
string Order { get; }
}
and got my models to implement it, the Order property just returns string representation of second order criteria, then I defined a view model:
public class GroupedCardList
{
public string CarName { get; set; }
public IEnumerable<ICarPurchaseOrdered> Cars { get; set; }
}
then I have a grouper that just groups my models:
public class CarGrouper
{
IEnumerable<GroupedCardList> Group(IEnumerable<ICarPurchaseOrdered> cars)
{
return cars.GroupBy(c => c.CarName)
.OrderBy(c => c.Key)
.Select(c => new GroupedCardList()
{
CarName = c.Key,
Cars = c.OrderBy(n => n.SystemId)
.ThenBy(n => n.Order)
});
}
}
But it doesn't work right because it sorts strings and I get the car purchase with Milage=1200 before the car with Milage=90.
I know that example is a little bit contrived but it perfectly represents the issue that I have right now. Please give me some advice.
One way to do it would be to implement a custom IComparer. If you extract a common base class:
public class Car
{
public string CarName { get; set; }
public string SystemId { get; set; }
}
public class CarRent : Car
{
public DateTime RentEndDate { get; set; }
}
public class CarPurchase : Car
{
public decimal Mileage { get; set; }
}
Then a IComparer<Car> implementation might look like this:
public class CarComparer : IComparer<Car>
{
public int Compare(Car x, Car y)
{
// compare by system id first
var order = string.Compare(x.SystemId, y.SystemId);
if (order != 0)
return order;
// try to cast both items as CarRent
var xRent = x as CarRent;
var yRent = y as CarRent;
if (xRent != null && yRent != null)
return DateTime.Compare(xRent.RentEndDate, yRent.RentEndDate);
// try to cast both items as CarPurchase
var xPurc = x as CarPurchase;
var yPurc = y as CarPurchase;
if (xPurc != null && yPurc != null)
return decimal.Compare(xPurc.Mileage, yPurc.Mileage);
// now, this is awkward
return 0;
}
}
You can then pass the comparer instance to List.Sort and Enumerable.OrderBy.
You can use int.Parse and order integers instead of strings
c.OrderBy(n => n.SystemId)
.ThenBy(n => int.Parse(n.Order))
The ICarPurchaseOrdered.Order used to order (then) by is a string type; Hence why the ordering is done alphabetically.
I would suggest to change the type of ICarPurchaseOrdered.Order to object,
so the Orderbycan use the underlying object (eitherDateTimeorDecimal`) to order.
**Update:
Try this
c.OrderBy(n => n.SystemId)
.ThenBy(n => n.GetType())
.ThenBy(n => n.Order);
I have this item:
public partial class PACK
{
public int PACK_IDE { get; set; }
public string PACK_DESCR { get; set; }
public Nullable<System.DateTime> PACK_DATE_CREATED { get; set; }
public Nullable<System.DateTime> PACK_DATE_MODIFIED { get; set; }
public Nullable<System.DateTime> PACK_DATE_LAST_CALC { get; set; }
public decimal PACK_COST { get; set; }
public int PACK_QTY_POSS { get; set; }
public string PACK_NOTE { get; set; }
public int PACK_QTY_SOLD { get; set; }
public decimal PACK_AVRG_SELL_PRICE { get; set; }
public Nullable<int> PACK_DESTINATION { get; set; }
public virtual ICollection<INVENTORY_PACK> INVENTORY_PACK { get; set; }
}
Which contains, as you can see, a list of Inventory Packs which are shaped like this:
public partial class INVENTORY_PACK
{
public int INVENT_PACK_IDE { get; set; }
public int INVENT_IDE { get; set; }
public int PACK_IDE { get; set; }
public int QTY { get; set; }
public virtual INVENTORY INVENTORY { get; set; }
public virtual PACK PACK { get; set; }
}
And, lastly, the Inventory Items, which has 2 important fields that are of importance right now:
public partial class INVENTORY
{
public int INVENT_IDE { get; set; }
public Nullable<int> CARD_IDE { get; set; }
public Nullable<int> INVENT_NB_IN_STOCK { get; set; }
public Nullable<int> INVENT_NB_QT_SOLD { get; set; }
public string INVENT_ITEM_STATE { get; set; }
public virtual CARD CARD { get; set; }
public virtual ICollection<INVENTORY_PACK> INVENTORY_PACK { get; set; }
}
When I actually save or create a new pack, I need to find a way to check if the actual pack exists that has the exact same Inventory Items based on INVENT_ITEM_STATE and CARD_IDE and, also, of QTY in INVENTORY_PACK. If these three values are identical, then we may consider having the same children. I basically need to search through any Packs (using Linq or any Linq-To-Sql call) which childrens are the same as the one I have right now, but I don't really know how to do this except for massive mind-blowing for/foreach loops.
EDIT
As requested, here's an example of what I've been trying to do.
internal void CreatePack(PackInfo _pack)
{
using (TransactionScope scope = TransactionUtils.CreateTransactionScope())
{
try
{
var packQry = from pa in mDb.PACK
select pa;
if (!packQry.Any())
{
PACK packToAdd = DataConverter.PackInfoToPACKData(_pack);
mDb.PACK.Add(packToAdd);
mDb.SaveChanges();
int packID = mDb.PACK.Max(_x => _x.PACK_IDE);
foreach (INVENTORY_PACK inventoryPack in packToAdd.INVENTORY_PACK)
{
inventoryPack.PACK_IDE = packID;
mDb.SaveChanges();
}
}
else
{
List<PACK> listPacks = new List<PACK>();
foreach (var inventoryPackInfo in _pack.mListInventoryPackInPack)
{
packQry = from pa in mDb.PACK
where pa.INVENTORY_PACK.Any(_item =>
_item.INVENTORY.INVENT_IDE ==
inventoryPackInfo.mInventoryItem.mInventoryID)
where pa.INVENTORY_PACK.Any(
_item =>
_item.INVENTORY.INVENT_ITEM_STATE ==
inventoryPackInfo.mInventoryItem.mItemState)
where pa.INVENTORY_PACK.Any(_item => _item.QTY == inventoryPackInfo.mQuantity)
select pa;
if (packQry.Any())
{
listPacks.AddRange(packQry);
}
}
if (_pack.mListInventoryPackInPack.Count == 1)
{
}
IDictionary<PACK, int> counts = new Dictionary<PACK, int>();
foreach (var pack in listPacks)
{
if (!counts.ContainsKey(pack))
{
counts.Add(pack, 1);
}
else
{
counts[pack]++;
}
}
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
scope.Complete();
}
}
EXAMPLE
I think that I need to clarify my need. Here's an example.
Say that I have 1 PACK containing 2 INVENTORY_PACK: 1 is an INVENTORY item with INVENT_IDE 1234, CARD_IDE 4321, QTY is 1, and INVENT_ITEM_STATE is PERFECT. The second object is INVENT_IDE 4567, CARD_IDE 7654, QTY is 2 and INVENT_ITEM_STATE PERFECT.
I need to check through the packages to see if there's already a package containing exactly there two items in the selected parameters. So there are many possibilities:
If we have another existing PACK that has the same items and the same number of items (in this case, 2), quantities and IDS, we have a perfect match and we consider that the PACK already exists;
If there is a PACK containing the same items, but with another one (3 items or more for this example), is it considered another pack; then we do not have a match;
If any package has only one of these items, we do not have a match.
If I understand well, you could do the following :
Implement two EqualityComparer (may be implemented in your business layer as it's business logic only)
class PACK_Comparer : EqualityComparer<PACK>
{
public override bool Equals(PACK p1, PACK p2)
{
// Two PACK are Equals if their INVENTORYs contains the same INVENTORY items
return (p1.INVENTORY_PACK.Count() == p2.INVENTORY_PACK.Count()
&& p1.INVENTORY_PACK.Intersect(p2.INVENTORY_PACK, new INVENTORY_PACK_Comparer()).Count() == p1.INVENTORY_PACK.Count());
}
public override int GetHashCode(PACK p)
{
// Ensure that if the Equals method returns true for two PACK p1 and p2
// then the value returned by the GetHashCode method for p1 must equal the value returned for p2
INVENTORY_PACK_Comparer comp = new INVENTORY_PACK_Comparer();
int hCode = 0;
foreach (var i in p.INVENTORY_PACK)
hCode ^= comp.GetHashCode(i);
return hCode.GetHashCode();
}
}
class INVENTORY_PACK_Comparer : EqualityComparer<INVENTORY_PACK>
{
public override bool Equals(INVENTORY_PACK i1, INVENTORY_PACK i2)
{
// Two INVENTORY_PACK are Equals if their INVENT_ITEM_STATE, CARD_IDE and QTY are Equals
return (i1.INVENTORY.INVENT_ITEM_STATE == i2.INVENTORY.INVENT_ITEM_STATE
&& i1.INVENTORY.CARD_IDE == i2.INVENTORY.CARD_IDE
&& i1.QTY == i2.QTY);
}
public override int GetHashCode(INVENTORY_PACK i)
{
// Ensure that if the Equals method returns true for two INVENTORY_PACK i1 and i2
// then the value returned by the GetHashCode method for i1 must equal the value returned for i2
int hCode = i.INVENTORY.INVENT_ITEM_STATE.GetHashCode()
^ i.INVENTORY.CARD_IDE.GetHashCode()
^ i.QTY.GetHashCode();
return hCode.GetHashCode();
}
}
Then check if a same PACK already exist is as short as
bool exist = mDb.PACK.Contains(_pack, new PACK_Comparer());
And if you want to fetch the actual PACK which already exist in your mDb :
PACK_Comparer comp = new PACK_Comparer();
PACK existingPack = mDb.PACK.FirstOrDefault(p => comp.Equals(p, _pack));
Note that I removed the 'test is null' things to make it simplier.
You'll need to implement this on your own.
Regards,
Gerard
This is probably what you want
int count = (from p in _pack.INVENTORY_PACK
where pack.INVENTORY.INVENT_ITEM_STATE == p.INVENTORY.INVENT_ITEM_STATE
select p).Count();
After that check for if(pack.QTY == count)