Getting Index out of range exception - c#

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.

Related

C# how to check array in list

I'm building a Worker service for Windows who gets data from another program on the system.
at this point i have all data that is need now i want to keep a list with up to date data.
When i run the application for the Zones i get System.Int32[] what i would love to see is the data from System.Int32[]
how to obtain this?
List<BroadcastModel> activeOmroep = new List<BroadcastModel>();
for (int o = 0; o < webcontent.Length; o++)
{
for (int i = 0; i < webcontent[o].Zones.Length; i++)
{
}
activeOmroep.Add(new BroadcastModel
{
Id = webcontent[o].Id,
Name = webcontent[o].Name,
Recording = webcontent[o].Recording,
Zones = webcontent[o].Zones
}) ;
My BroadcastModel class looks like the following:
public class BroadcastModel
{
public int Id { get; set; }
public string Name { get; set; }
public int[] Channels { get; set; }
public bool Recording { get; set; }
public int Type { get; set; }
public int Volume { get; set; }
public int[] Zones { get; set; }
}
Thanks in advance.
for testing purpose i added the following:
foreach (var omroep in activeOmroep)
{
Console.WriteLine("Broadcast ID: " + omroep.Id);
Console.WriteLine("Broadcast Name: " + omroep.Name);
Console.WriteLine("Broadcast is recording: " + omroep.Recording);
Console.WriteLine("Broadcast Zones: " + omroep.Zones);
Console.WriteLine("****************************");
}
but then i got the system.int32[]
Whenever you are printing data using Console.WriteLine(), it calls .ToString() method, if .ToString() is not overridden then it calls Object.ToString() method. Object.ToString() prints type in the string format.
In your case Console.WriteLine("Broadcast Zones: " + omroep.Zones); is printing System.Int32[], because it is calling ToString() method with the basic behavior.
To solve your issue, I would suggest to Override ToString() method in BroadcastModel class and return string which you want to print.
To print array elements, use string.Join() method.
Concatenates the elements of a specified array or the members of a
collection, using the specified separator between each element or
member.
public class BroadcastModel
{
public int Id { get; set; }
public string Name { get; set; }
public int[] Channels { get; set; }
public bool Recording { get; set; }
public int Type { get; set; }
public int Volume { get; set; }
public int[] Zones { get; set; }
public override string ToString()
{
return $"ID : {this.Id}, \nName: {this.Name} \nIs recording: {this.Recording} \nZones : {string.Join(", ", this.Zones)}";
}
}
Now you can print List<BroadcastModel> using foreach loop,
foreach(var broadcastmodel in activeOmroep)
Console.WriteLine(broadcastmodel);

Initialize Nested List<T>

Please refer the below code
List<ProductDM> productDMList = _orderRepo.GetProductList(32, 12);
for (int i=0;i<productDMList.Count;i++)
{
productDMList[i].CabinetList[i].Min = productDMList[i].Min;
productDMList[i].CabinetList[i].Max = productDMList[i].Max;
}
public class ProductDM
{
public List<InventoryDM> CabinetList { get; set; }
public double Min { get; set; }
public double Max { get; set; }
}
public class InventoryDM
{
public Double Min { get; set; }
public Double Max { get; set; }
}
The requirement is to loop through the productDMList and bind the returned MIN and MAX values inside the cabinet list. ProductDM fills with MIN and MAX amounts but when assigning those to CabinetList, it returns an error.
This is because the CabinetList is initially empty and it doesn't show the MIN MAX properties in it.
I am using the above code to assign data but returns
Object reference not set to an instance of an object.
because of the CabinetList empty.
How to initialize the cabinet list here???
As Marco Forberg's answer states initializing the CabinetList in the constructor prevents the
Object reference not set to an instance of an object.
exception.
In addition to this, instead of assigning the Min and Max values via the index accessor:
productDMList[i].CabinetList[i].Min = productDMList[i].Min;
productDMList[i].CabinetList[i].Max = productDMList[i].Max;
You should use the Add() method of the List<> type:
productDMList[i].CabinetList.Add(new InventoryDM { Min = productDMList[i].Min, Max = productDMList[i].Max });
otherwise you will get an
ArgumentOutOfRangeException
because you try to access an item on the list which doesn't exist yet.
Depending on your requirements you could do something like this
public class ProductDM
{
public List<InventoryDM> CabinetList { get; private set; }
public double Min { get; set; }
public double Max { get; set; }
public ProductDM()
{
CabinetList = new List<InventoryDM>();
}
}
or if you get your CabinetList data from an external source, e.g. database:
public class ProductDM
{
private List<InventoryDM> _cabinetList = null;
public double Min { get; set; }
public double Max { get; set; }
public List<InventoryDM> CabinetList
{ get
{
if(_cabinetList == null)
{
_cabinetList = ... // retrieve data from external source
}
return _cabinetList;
}
}
}
The issue is not the emptiness of the CabinetList, instead the list of objects is null as you can see in the debugger.
In order to initialize the list you can refer to the answers of this post:
How to initialize a C# string list (List<string>) with many string values
Note that you don't have a list of string but a list of <InventoryBM> objects, but the concept is analogous.

How to get list from nested list with highest length?

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

Storing/retrieving a JSON string in the database making it easy to work with in code

I have a c# object 'Product' with a property called: Offset
In the database the field is of type nvarchar(50)
I will be storing a JSON value in it such as the following: { "y": 0, "m": 0, "d": 0 }
I would like to know a good way of working with a property like this in my code. Here is how I currently am doing it:
public class Product
{
public int Id {get; set;}
public string Description {get; set;}
public decimal Price {get; set;}
public int OffsetYears { get; set; }
public int OffsetMonths { get; set; }
public int OffsetDays { get; set; }
public string Offset
{
get
{
Offset offset = new Offset()
{
Y = OffsetYears,
M = OffsetMonths,
D = OffsetDays
};
return JsonConvert.SerializeObject(offset);
}
set
{
OffsetObj offset = JsonConvert.DeserializeObject<Offset>(value);
OffsetYears = offset.Y;
OffsetMonths = offset.M;
OffsetDays = offset.D;
}
}
private class OffsetObj
{
public int Y { get; set; }
public int M { get; set; }
public int D { get; set; }
}
}
So then when I accept values from the User in the UI I would set the OffsetYears, OffsetMonths, and OffsetDays properties.. So in my repository I can just save Offset.
And when retrieving values from the database I will simply work with OffsetYears, OffsetMonths, and OffsetDays properties in my code.
Is there a better way to handle this sort of thing? I just feel like I am not utilizing all of my c# resources. Like what if another developer accidentally sets Offset through the code assuming any format of string can go in it.
Or am I better off just creating 3 separate integer fields in the database and avoiding all of this...
I would hold the values in a field of your private type. Consider this approach:
public class Product
{
private OffsetObj _offset = new OffsetObj();
public int Id { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
public int OffsetYears
{
get { return _offset.Y; }
set { _offset.Y = value; }
}
public int OffsetMonths
{
get { return _offset.M; }
set { _offset.M = value; }
}
public int OffsetDays
{
get { return _offset.D; }
set { _offset.D = value; }
}
public string Offset
{
get
{
return JsonConvert.SerializeObject(_offset);
}
set
{
_offset = JsonConvert.DeserializeObject<OffsetObj>(value);
}
}
private class OffsetObj
{
public int Y { get; set; }
public int M { get; set; }
public int D { get; set; }
}
}
This way, the field offset will hold the values for the offset.
Like what if another developer accidentally sets Offset through the code assuming any format of string can go in it.
JsonConvert will throw a JsonReaderException if trying to set the Offset property to a string that does not match JSON-format. In my opinion this is expected. To clarify further, you could name your property to OffsetJson.
However, I fail to see the benefit in this simple case to store your information as JSON. If you are using a relational database, you may as well just store your values in separate columns.

An elegant way to check if any items which has the same childrens exist

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)

Categories

Resources