Cloning An Object which contains many objects and lists C# - c#

Hello there :) I'm having a problem when cloning an object that contains other objects and lists in winForm.
I want to Clone an Object of Type Structure the classes are provided below
first of all i have tried Shallow Clone
public Structure Clone()
{
return this.MemberwiseClone() as Structure;
}
put it didn't work so i searched https://stackoverflow.com/ and i did a deep clone
Deep cloning objects
and this
How do you do a deep copy of an object in .NET (C# specifically)?
public static T DeepClone<T>(T obj)
{
using (var ms = new MemoryStream())
{
var formatter = new BinaryFormatter();
formatter.Serialize(ms, obj);
ms.Position = 0;
return (T) formatter.Deserialize(ms);
}
}
The Problem that I'm having is i am taking a backup copy of an object
var backup=DeepClone<Structure>(this.sched); //sched is Structure Object
and then changing this.sched the backup is changed :(
the structre of my classes is:
[Serializable]
public class Sub
{
string name;
int studentsNumber;
int unassaignedStudent;
public Sub(string name, int number)
{
this.name = name;
this.studentsNumber = number;
this.unassaignedStudent = number;
}
public Subject()
{
this.name = "";
this.studentsNumber = 0;
this.unassaignedStudent = 0;
}
public bool Assigne(int count)
{
//stuff
}
public Sub Clone()
{
return this.MemberwiseClone() as Sub;
}
}
[Serializable]
class Room
{
string name;
int studentsNumber;
int full;
private int freeSeats;
List<Sub> subjects;
/// <summary>
/// the list of subjects
/// </summary>
internal List<Sub> Subjects
{
get { return subjects; }
set { subjects = value; }
}
Dictionary<Subject, int> variations;
public Room(string name, int number)
{
this.name = name;
this.studentsNumber = number;
this.full = 0;
this.subjects = new List<Subject>();
this.variations = new Dictionary<Subject, int>();
this.freeSeats = number;
}
public Room(int number)
{
this.studentsNumber = number;
this.full = 0;
this.subjects = new List<Subject>();
this.variations = new Dictionary<Subject, int>();
this.freeSeats = number;
}
public Room()
{
this.name = "R" + count.ToString();
count++;
this.studentsNumber = 0;
this.full = 0;
this.subjects = new List<Sub>();
this.variation= new Dictionary<Sub, int>();
this.freeSeats = 0;
}
public bool addSubject(Sub sbj)
{
//also stuff
}
public bool addPartialSubject(Sub sbj)
{
//stuff
// return false;
}
public Room Clone()
{
return this.MemberwiseClone() as Room;
}
}
[Serializable]
class Period
{
List<Room> rooms;
int conflicts;
List<Sub> subjects;
internal List<Sub> Subjects
{
get { return subjects; }
set { subjects = value; }
}
/// <summary>
/// Create an instance of class Period
/// </summary>
/// <param name="rooms">the rooms in this Period</param>
public Period(List<Room> rooms)
{
this.conflicts = 0;
this.rooms = rooms;
subjects = new List<Subject>();
fillSubjects(ref rooms, ref subjects);
}
public Period()
{
this.conflicts = 0;
this.rooms = null;
subjects = new List<Subt>();
freeSeats = 0;
}
/// <summary>
/// Fill the subjects in the rooms to the list of subjects
/// </summary>
/// <param name="rooms">referance to the list of the rooms</param>
/// <param name="subjects">referance to the list of the subjects</param>
private void fillSubjects(ref List<Room> rooms, ref List<Sub> subjects)
{
foreach (var room in rooms)
{
foreach (var subject in room.Subjects)
{
if (!subjects.Exists(s => s.Name == subject.Name))
subjects.Add(subject);
}
}
}
/// <summary>
/// Adds the given subject to the period if there is a place in any room
/// </summary>
/// <param name="s">the subject to add</param>
/// <returns>true if there is space for this subject and added, otherwise false</returns>
public bool AddSubject(Sub s)
{
foreach (var room in rooms)
{
if (room.addSubject(s))
{
//stuff
}
else
if (room.addPartialSubject(s))
{
//stuff
}
}
return false;
}
private int CalculateConflictions(Sub s)
{
//also a lot of stuff
}
}
[Serializable]
class Structure:IDisposable
{
int days;
/// <summary>
/// the number of days in the Schedual
/// </summary>
public int Days
{
get { return days; }
set { days = value; }
}
int periods;
Period[,] schedualArray;
List<Room> rooms;
internal List<Room> Rooms
{
get { return rooms; }
set { rooms = value; }
}
/// <summary>
/// Creates an instance of the Structure object
/// </summary>
/// <param name="rooms">a list of the rooms in the Schedual</param>
public Structure(int days, int periods,List<Room> rooms)
{
this.days = days;
this.periods = periods;
this.rooms=rooms;
this.schedualArray = new Period[days, periods];
this.subjectCount = 0;
for (int i = 0; i < days; i++)
{
for (int j = 0; j < periods; j++)
{
schedualArray[i, j] = new Period(CloneList(ref rooms)); //here i cloned the list to be in the safe side and it didn't work also
}
}
}
public Structure()
{
this.days = 0;
this.totalEval = Int32.MaxValue;
this.periods = 0;
this.rooms = null;
this.subjectCount = 0;
this.schedualArray = null;
}
internal bool AddSubject(Sub subject, int day, int period)
{
//add the subject into inner lists (room)
}
public void PrintStruct()
{
for (int i = 0; i < days; i++)
{
for (int j = 0; j < periods; j++)
{
foreach (var subject in schedualArray[i, j].Subjects)
{
Console.Write("\t\t");
}
Console.Write("\t\t");
}
Console.WriteLine();
}
}
public Structure Clone()
{
return this.MemberwiseClone() as Structure;
}
public List<Room> CloneList(ref List<Room> rooms)
{
var lst = new List<Room>();
foreach (var room in rooms)
{
lst.Add(DeepClone<Room>(room));
}
return lst;
}
internal void RemoveSubject(Sub subject)
{
//..................
}
#region IDisposable Members
public void Dispose()
{
GC.Collect(g, GCCollectionMode.Forced);
}
#endregion
}
I don't really now what are the details of the cloning process but my requirement is to clone the entire object with the successive objects in the structure and hirarachy of the object and the complete items that the list points to not only there references
Please Can anyone help me please I'm really lost:(, thanks in advance to everyone interested in helping me :) Yaser
EDIT when using the method #WiiMaxx
Structure backup=XamlClone(this.sched);
private Structure XamlClone(Structure s)
{
//First Step
// create a XAML string
string stCopie = XamlWriter.Save(s);
//Secound Step
// convert him back to an Object of YourTyp
return XamlReader.Load(XmlReader.Create(new StringReader(stCopie))) as Structure;
}
but the inner period[,] is cloned as null
Can you please help me #WiiMaxx
Edit 2.0
i have also checked this article about deep cloning in 3 methods and i think i have circular references in my code that is why this isn't working for me
http://blog.nuclex-games.com/mono-dotnet/fast-deep-cloning/
End Edit

Ok now it should really work
(i deleted also my old solution because it was totally wrong for your needs)
Sub.cs
public class Sub: ICloneable
{
struct datenStruct
{
internal int studentsNumber;
internal int unassaignedStudent;
internal string name;
}
private datenStruct USE;
int studentsNumber;
public string Name
{
get { return USE.name; }
set { USE.name = value; }
}
private Sub(datenStruct struc)
{
this.USE = struc;
}
public Sub(string name, int number)
{
this.USE = new datenStruct();
this.USE.name = name;
this.USE.studentsNumber = number;
this.USE.unassaignedStudent = number;
}
public bool Assigne(int count)
{
//stuff
return true;
}
public object Clone()
{
var copie = new datenStruct();
copie.name = USE.name;
copie.unassaignedStudent = USE.unassaignedStudent;
copie.studentsNumber = USE.studentsNumber;
return new Sub(copie);
}
}
Room.cs
public class Room: ICloneable
{
struct datenStruct
{
internal int studentsNumber;
internal int full;
internal string name;
internal int freeSeats;
internal List<Sub> subjects;
internal Dictionary<Sub, int> variations;
}
private datenStruct USE;
/// <summary>
/// the list of subjects
/// </summary>
internal List<Sub> Subjects
{
get { return USE.subjects; }
set { USE.subjects = value; }
}
public Room(string name, int number)
{
this.USE = new datenStruct();
this.USE.name = name;
this.USE.studentsNumber = number;
this.USE.full = 0;
this.USE.subjects = new List<Sub>();
this.USE.variations = new Dictionary<Sub, int>();
this.USE.freeSeats = number;
}
public Room(int number)
{
this.USE = new datenStruct();
this.USE.studentsNumber = number;
this.USE.full = 0;
this.USE.subjects = new List<Sub>();
this.USE.variations = new Dictionary<Sub, int>();
this.USE.freeSeats = number;
}
private Room(datenStruct struc)
{
USE = struc;
}
public bool addSubject(Sub sbj)
{
//also stuff
return false;
}
public bool addPartialSubject(Sub sbj)
{
//stuff
return false;
}
public object Clone()
{
var copie = new datenStruct();
copie.studentsNumber = USE.studentsNumber;
copie.full = USE.full;
copie.freeSeats = USE.freeSeats;
var SubListCopie = new List<Sub>();
foreach (Sub origSub in USE.subjects)
SubListCopie.Add((Sub)origSub.Clone());
copie.subjects = SubListCopie;
var SubDictCopie = new Dictionary<Sub, int>();
foreach (KeyValuePair<Sub, int> KvP in USE.variations)
SubDictCopie.Add((Sub)KvP.Key.Clone(),KvP.Value);
copie.variations = SubDictCopie;
return new Room(copie);
}
}
Period.cs
public class Period: ICloneable
{
struct datenStruct
{
internal List<Room> rooms;
internal List<Sub> subjects;
internal string name;
internal int conflicts;
}
private datenStruct USE;
internal List<Sub> Subjects
{
get { return USE.subjects; }
set { USE.subjects = value; }
}
/// <summary>
/// Create an instance of class Period
/// </summary>
/// <param name="rooms">the rooms in this Period</param>
public Period(List<Room> rooms)
{
this.USE.conflicts = 0;
this.USE.rooms = rooms;
this.USE.subjects = new List<Sub>();
fillSubjects(ref USE.rooms, ref USE.subjects);
}
private Period(datenStruct struc)
{
USE = struc;
}
/// <summary>
/// Fill the subjects in the rooms to the list of subjects
/// </summary>
/// <param name="rooms">referance to the list of the rooms</param>
/// <param name="subjects">referance to the list of the subjects</param>
private void fillSubjects(ref List<Room> rooms, ref List<Sub> subjects)
{
foreach (var room in rooms)
{
foreach (var subject in room.Subjects)
{
if (!subjects.Exists(s => s.Name == subject.Name))
subjects.Add(subject);
}
}
}
/// <summary>
/// Adds the given subject to the period if there is a place in any room
/// </summary>
/// <param name="s">the subject to add</param>
/// <returns>true if there is space for this subject and added, otherwise false</returns>
public bool AddSubject(Sub s)
{
foreach (var room in USE.rooms)
{
if (room.addSubject(s))
{
//stuff
}
else
if (room.addPartialSubject(s))
{
//stuff
}
}
return false;
}
private int CalculateConflictions(Sub s)
{
//also a lot of stuff
return 1;
}
public object Clone()
{
var copie = new datenStruct();
copie.name = USE.name;
copie.conflicts = USE.conflicts;
var RoomListCopie = new List<Room>();
foreach (Room origSub in USE.rooms)
RoomListCopie.Add((Room)origSub.Clone());
copie.rooms = RoomListCopie;
var SubListCopie = new List<Sub>();
foreach (Sub origSub in USE.subjects)
SubListCopie.Add((Sub)origSub.Clone());
copie.subjects = SubListCopie;
return new Period(copie);
}
}
Structure.cs
public class Structure : IDisposable,ICloneable
{
struct datenStruct
{
internal int days;
internal int subjectCount;
internal int periods;
internal Period[,] schedualArray;
internal List<Room> rooms;
}
private datenStruct USE;
/// <summary>
/// the number of days in the Schedual
/// </summary>
public int Days
{
get { return USE.days; }
set { USE.days = value; }
}
internal List<Room> Rooms
{
get { return USE.rooms; }
set { USE.rooms = value; }
}
/// <summary>
/// Creates an instance of the Structure object
/// </summary>
/// <param name="rooms">a list of the rooms in the Schedual</param>
public Structure(int days, int periods, List<Room> rooms)
{
this.USE.days = days;
this.USE.periods = periods;
this.USE.rooms = rooms;
this.USE.schedualArray = new Period[days, periods];
this.USE.subjectCount = 0;
for (int i = 0; i < days; i++)
{
for (int j = 0; j < periods; j++)
{
USE.schedualArray[i, j] = new Period(CloneList(ref rooms)); //here i cloned the list to be in the safe side and it didn't work also
}
}
}
private Structure(datenStruct struc)
{
this.USE = struc;
}
internal bool AddSubject(Sub subject, int day, int period)
{
//add the subject into inner lists (room)
return true;
}
public void PrintStruct()
{
for (int i = 0; i < USE.days; i++)
{
for (int j = 0; j < USE.periods; j++)
{
foreach (var subject in USE.schedualArray[i, j].Subjects)
{
Console.Write("\t\t");
}
Console.Write("\t\t");
}
Console.WriteLine();
}
}
public List<Room> CloneList(ref List<Room> rooms)
{
var lst = new List<Room>();
foreach (var room in rooms)
{
lst.Add((Room)room.Clone());
}
return lst;
}
internal void RemoveSubject(Sub subject)
{
//..................
}
#region IDisposable Members
public void Dispose()
{
// GC.Collect(g, GCCollectionMode.Forced);
}
#endregion
public object Clone()
{
var copie =new datenStruct();
copie.days = USE.days;
copie.subjectCount = USE.subjectCount;
copie.periods = USE.periods;
var RoomListCopie = new List<Room>();
foreach (Room origSub in USE.rooms)
RoomListCopie.Add((Room)origSub.Clone());
copie.rooms = RoomListCopie;
copie.schedualArray = new Period[copie.days, copie.periods];
for (int i = 0; i < copie.days; i++)
{
for (int j = 0; j < copie.periods; j++)
{
copie.schedualArray[i, j] = new Period(CloneList(ref copie.rooms));
}
}
return new Structure(copie);
}
}

i wrote this code i think it solve my problem but if you have any other answers please inform me.
private Structure SpecialClone(Structure s)
{
var rooms = Cloner.DeepClone<List<Room>>(s.Rooms);
var perds = Cloner.DeepClone<Period[,]>(s.SchedualArray);
var days = s.Days;
var periods = s.Periods;
return new Structure(days, periods, rooms, perds, s.SubjectCount);
}
and i added an overloading to the Structure Constructure to do this:
public Structure(int days, int periods, List<Room> rooms, Period[,] _periods,int subjectCount)
{
this.days = days;
this.periods = periods;
this.rooms = rooms.DeepClone();
this.subjectCount = subjectCount;
this.schedualArray = _periods.Clone() as Period[,];
}

Related

sorting a generic list from within a generic container class

I need to sort a list by any one of its properties, but i dont know which of these properties it will specifically be sorted on. The Main method below.
static void Main(string[] args)
{
Things<Something> something = new Things<Something>();
something.Add(new Something
{ Thing = "Apartment", Price = 1500000 });
something.Add(new Something
{ Thing = "Bed", Price = 10000 });
something.Add(new Something
{ Thing = "Lamp", Price = 600 });
something.Add(new Something
{ Thing = "Car", Price = 5000000 });
Console.WriteLine("\n\tStuff sorted by description");
something = something.SelectionSort("Thing");
foreach (Something thing in something)
Console.WriteLine("\t" + thing);
Console.WriteLine("\n\tStock items sorted by value");
something = something.SelectionSort("Value");
foreach (Something thing in something)
Console.WriteLine("\t" + thing);
Console.Write("\n\tPress any key to exit ...");
Console.ReadKey();
}
I have a struct
public struct Something
{
public string Thing { get; set; }
public decimal Price { get; set; }
}
And a generic container class called things
public class Things<T> : IEnumerable<T>
{
private List<T> lstItems;
public int Count { get { return lstItems.Count; } }
public Things() { lstItems = new List<T>(); }
public Things(List<T> items_) { lstItems = new List<T>(items_); }
public void Add(T item)
{
lstItems.Add(item);
}
public T this[int i]
{
get { return lstItems[i]; }
set { lstItems[i] = value; }
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new System.NotImplementedException();
}
public IEnumerator<T> GetEnumerator()
{
foreach (T item in lstItems)
yield return item;
}
}
An extensions class extends the generic container class
public static class ExtensionsClass
{
private static string SortFiield { get; set; }
private static object GetProperty<T>(T thing, string nameofProp)
{
return thing.GetType().GetProperty(nameofProp).GetValue(thing, null);
}
private static int Compare<T>(T x, T y)
{
IComparable propX = (IComparable)GetProperty(x, SortFiield);
IComparable propY = (IComparable)GetProperty(y, SortFiield);
return propX.CompareTo(propY);
}
public static Things<T> SelectionSort<T>(this Things<T> things, string SORTFIELD)
{
List<T> lsstt = new List<T>(things);
int iIndex;
T temporary;
SortFiield = SORTFIELD;
for (int i = 0; i < lsstt.Count - 1; i++)
{
iIndex = i;
for (int j = i + 1; j < lsstt.Count; j++)
{
string first = GetProperty(lsstt[j], SortFiield).ToString();
string second = GetProperty(lsstt[iIndex], SortFiield).ToString();
if (Compare(first, second) < 0)
iIndex = j;
}
temporary = lsstt[i];
lsstt[i] = lsstt[iIndex];
lsstt[iIndex] = temporary;
}
return new Things<T>(lsstt);
}
}
The problem i am encountering is that get property in the extension class returns null, but i know that the object i am trying to return exists. It is found by the "String first = ...." line but when getproperty is called from the Compare method then it returns null.
You are passing "first", "second" to Compare. In your case both of them are strings and not objects, you need to pass "lsstt[j]" and "lsstt[iIndex]" to it.
if (Compare(lsstt[j], lsstt[iIndex]) < 0)
iIndex = j;

JSON serializing of objects with huge IEnumerable is very slow

I would like to serialize the Result object into JSON but it takes a lot of time, like more than 1 minute when the whole process just take 1.5 seconds without the serializing part.
I have tried using Json.NET and fastJSON but both with the same slowness.
IEnumerable<IEnumerable<int>> geometry in ResultFeature can be really huge as it can contains dozens of thousands of integers.
Why does it takes that long?
using System;
using System.Collections.Generic;
using fastJSON;
using ESRI.ArcGIS.ADF;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.esriSystem;
namespace DesktopConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var watch = System.Diagnostics.Stopwatch.StartNew();
Result result = new Result
{
fields = new List<string>
{
"CD_MUNCP",
"NOM_MUNCP"
},
features = CreateResultFeatures().ToList()
};
string json = JSON.ToJSON(result);
watch.Stop();
Console.WriteLine(watch.ElapsedMilliseconds);
Console.ReadLine();
}
public class Result
{
public List<string> fields { get; set; }
public string geometryType { get; set; }
public IEnumerable<ResultFeature> features { get; set; }
}
public class ResultFeature
{
public Dictionary<string, dynamic> attributes { get; set; }
public IEnumerable<IEnumerable<int>> geometry { get; set; }
}
public static IEnumerable<ResultFeature> CreateResultFeatures()
{
IWorkspace gdbWorkspace = FileGdbWorkspaceFromPath(#"\\vnageop1\geod\Maxime\test.gdb");
IFeatureWorkspace featureWorkspace = (IFeatureWorkspace)gdbWorkspace;
IFeatureClass featureClass = featureWorkspace.OpenFeatureClass(#"GEO09E04_MUNCP_GEN");
IQueryFilter queryFilter = new QueryFilterClass();
queryFilter.SubFields = "CD_MUNCP, NOM_MUNCP, SHAPE";
int cd_muncp_idx = featureClass.FindField("CD_MUNCP");
int nom_muncp_idx = featureClass.FindField("NOM_MUNCP");
using (ComReleaser comReleaser = new ComReleaser())
{
IFeatureCursor cursor = featureClass.Search(queryFilter, false);
comReleaser.ManageLifetime(cursor);
IFeature feature = null;
while ((feature = cursor.NextFeature()) != null)
{
ResultFeature resultFeature = new ResultFeature
{
attributes = new Dictionary<string,dynamic>
{
{ "CD_MUNCP", Convert.ToString(feature.Value[cd_muncp_idx]) },
{ "NOM_MUNCP", Convert.ToString(feature.Value[nom_muncp_idx]) }
},
geometry = PolygonToDeltas(feature.Shape as IPolygon4).ToLiist()
};
yield return resultFeature;
}
}
}
public static IEnumerable<IEnumerable<int>> PolygonToDeltas(IPolygon4 polygon)
{
IGeometryBag exteriorRingGeometryBag = polygon.ExteriorRingBag;
IGeometryCollection exteriorRingGeometryCollection = exteriorRingGeometryBag as IGeometryCollection;
for (int i = 0; i < exteriorRingGeometryCollection.GeometryCount; i++)
{
IGeometry exteriorRingGeometry = exteriorRingGeometryCollection.get_Geometry(i);
IPointCollection exteriorRingPointCollection = exteriorRingGeometry as IPointCollection;
yield return CreateDeltas(exteriorRingPointCollection);
IGeometryBag interiorRingGeometryBag = polygon.get_InteriorRingBag(exteriorRingGeometry as IRing);
IGeometryCollection interiorRingGeometryCollection = interiorRingGeometryBag as IGeometryCollection;
for (int k = 0; k < interiorRingGeometryCollection.GeometryCount; k++)
{
IGeometry interiorRingGeometry = interiorRingGeometryCollection.get_Geometry(k);
IPointCollection interiorRingPointCollection = interiorRingGeometry as IPointCollection;
yield return CreateDeltas(interiorRingPointCollection);
}
}
}
private static IEnumerable<int> CreateDeltas(IPointCollection pointCollection)
{
int previous_x = (int)pointCollection.get_Point(0).X;
int previous_y = (int)pointCollection.get_Point(0).Y;
yield return previous_x;
yield return previous_y;
for (int i = 1; i < pointCollection.PointCount; i++)
{
int current_x = (int)pointCollection.get_Point(i).X;
int current_y = (int)pointCollection.get_Point(i).Y;
yield return previous_x - current_x;
yield return previous_y - current_y;
previous_x = current_x;
previous_y = current_y;
}
}
}
}

C# Compare two list and return value

I have a problem. I try compare two list currentItemsInColl and bPList. Inside bPList i have other list RequiredItems and now is what I need.
I want compare currentItemsInColl and RequiredItems and return bPList.craftingBlueprint.
I try Compare but I dont know how use it :/
using Devdog.InventoryPro;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CraftingAutoUpdate : MonoBehaviour {
public ItemCollectionBase itemCollection;
public ItemCollectionBase rewardCollection;
public CraftingCategory craftingCategory;
[Header("Blue Print List")]
public List<BlueprintList> bPList = new List<BlueprintList>();
public List<CurrentItemInCollList> currentItemsInColl = new List<CurrentItemInCollList>();
private CraftingBlueprint readyBlueprint;
public void OnShow()
{
GetBluePrint();
InvokeRepeating("StartUpdate",0f,0.05f);
}
public void OnHide()
{
CancelInvoke("StartUpdate");
}
private void StartUpdate()
{
UpdateDirectory();
UpdateFindMatchItems();
UpdateCraftResults();
}
private void GetBluePrint()
{
bPList.Clear();
foreach (var b in craftingCategory.blueprints)
{
if (b != null)
{
var rI = b.requiredItems;
var listReqItems = new List<RequiredItem>();
foreach (var e in rI)
{
listReqItems.Add(new RequiredItem(e.item.ID, e.amount));
}
bPList.Add(new BlueprintList(b.name, b, listReqItems));
}
}
}
private void UpdateDirectory()
{
currentItemsInColl.Clear();
foreach(var item in itemCollection)
{
if (item.item != null)
{
var cT = item.item.ID;
if (currentItemsInColl.Find(u =>u.itemID == cT) == null)
{
var itemCount = itemCollection.GetItemCount(item.item.ID);
currentItemsInColl.Add(new CurrentItemInCollList(item.item.ID, itemCount));
}
}
}
}
In this methode I try find same items in collections:
private void UpdateFindMatchItems()
{
readyBlueprint = null;
bool matchFailed = false;
int requiredItemCount = 0;
int currentItemsInCollCount = currentItemsInColl.Count;
foreach(var bp in bPList)
{
requiredItemCount = bp.RequiredItems.Count;
foreach(var rI in bp.RequiredItems)
{
if(CompareLists(currentItemsInColl, bp.RequiredItems))
{
print("aa");
}
print(currentItemsInCollCount);
}
}
private void UpdateCraftResults()
{
rewardCollection.Clear();
if (readyBlueprint != null)
{
foreach (var items in readyBlueprint.resultItems)
{
rewardCollection.AddItem(items.item,null,true,false);
}
}
}
I try somthing like this but is wont work with this lists:
public static bool CompareLists<T>(List<T> aListA, List<T> aListB)
{
if (aListA == null || aListB == null || aListA.Count != aListB.Count)
return false;
if (aListA.Count == 0)
return true;
Dictionary<T,T> lookUp = new Dictionary<T,T>();
// create index for the first list
for (int i = 0; i < aListA.Count; i++)
{
uint count = 0;
if (!lookUp.TryGetValue(aListA[i], out count))
{
lookUp.Add(aListA[i], 1);
continue;
}
lookUp[aListA[i]] = count + 1;
}
for (int i = 0; i < aListB.Count; i++)
{
uint count = 0;
if (!lookUp.TryGetValue(aListB[i], out count))
{
// early exit as the current value in B doesn't exist in the lookUp (and not in ListA)
return false;
}
count--;
if (count <= 0)
lookUp.Remove(aListB[i]);
else
lookUp[aListB[i]] = count;
}
// if there are remaining elements in the lookUp, that means ListA contains elements that do not exist in ListB
return lookUp.Count == 0;
}
}
And this is my lists:
/* LISTS */
[Serializable]
public class CurrentItemInCollList
{
public uint itemID;
public uint itemAmount;
public CurrentItemInCollList(uint newitemID, uint newItemAmount)
{
itemID = newitemID;
itemAmount = newItemAmount;
}
}
[Serializable]
public class BlueprintList
{
public string bluePrintName;
public CraftingBlueprint craftingBlueprint;
public List<RequiredItem> RequiredItems = new List<RequiredItem>();
public BlueprintList(string newBluePrintName, CraftingBlueprint newcraftingBlueprint, List<RequiredItem> list)
{
bluePrintName = newBluePrintName;
craftingBlueprint = newcraftingBlueprint;
RequiredItems = list;
}
}
[Serializable]
public class RequiredItem
{
public uint itemID;
public uint itemAmount;
public RequiredItem( uint newitemID, uint newItemAmount)
{
itemID = newitemID;
itemAmount = newItemAmount;
}
}
I forgot.. CurrentItemInCollList.itemAmount can be >= RequiredItems.itemAmount
Dictionary use hash values to compare objects.
The stored classes must implement public override int GetHashCode(){}
Use Linq - here is a small console example:
class Program
{
static void Main(string[] args)
{
//Required list
List<Order> currentItemsInColl = new List<Order>();
currentItemsInColl.Add(new Order() { Name = "bike1", Id = "01" });
currentItemsInColl.Add(new Order() { Name = "bike4", Id = "04" });
//List of all items
List<BPP> bPList = new List<BPP>();
bPList.Add(new BPP() { BikeName = "bike1", Idzzz = "01" });
bPList.Add(new BPP() { BikeName = "bike2", Idzzz = "02" });
bPList.Add(new BPP() { BikeName = "bike3", Idzzz = "03" });
bPList.Add(new BPP() { BikeName = "bike4", Idzzz = "04" });
bPList.Add(new BPP() { BikeName = "bike5", Idzzz = "05" });
//Blueprint List
List<BPP> Blueprint = new List<BPP>();
//get all items into the Blueprint list
foreach (Order i in currentItemsInColl)
{
List<BPP> tmp = bPList.FindAll(x => x.Idzzz.Contains(i.Id));
//here you add them all to a list
foreach (BPP item in tmp)
{
Blueprint.Add(item);
}
}
Console.ReadLine();
}
}
public class Order
{
public string Id { get; set; }
public string Name { get; set; }
}
public class BPP
{
public string Idzzz { get; set; }
public string BikeName { get; set; }
}
Sidenote: i am comparing the ID's in each of the lists! Hope it helps.

Writing a list of arrays using csvhelper C#

I am trying to write a List<double[]> into a csv file. Based on my experiments it is not possible using WriteRecords() directly, so I am looking for alternatives.
I cannot create a class to map this data because the number of elements in the arrays varies from execution to execution, and ranges from 1 to 75.
I have tried to go through each element of the array manually with WriteField() but it is really slow., and I have thousands of elements.
Is there anyway to accomplish this fast enough?
Thanks.
Edit:
Code
class ExportData
{
private Dictionary<int, Dictionary<SensorT, ListIndex>> _dict_sensorN;
private List<double[]> _values_list;
private int _current_max_Count=-1;
private static int _max_Count = 3000;
int n_columns = 0;
private CsvWriter csv;
public ExportData(List<SensorControl> sensorsUC)
{
//We create a dictionary with two keys that will store all the info from the sensors
_dict_sensorN = new Dictionary<int, Dictionary<SensorT, ListIndex>>();
foreach (SensorControl SensorC in sensorsUC)
{
Dictionary<SensorT, ListIndex> dict_sensorM = new Dictionary<SensorT, ListIndex>();
if (SensorC.emg)
{
ListIndex Index = new ListIndex();
Index.Column = n_columns;
Index.Row = 0;
dict_sensorM.Add(SensorT.EMG, Index);
n_columns++;
}
if (SensorC.triggers)
{
ListIndex Index = new ListIndex();
Index.Column = n_columns;
Index.Row = 0;
dict_sensorM.Add(SensorT.Trigger1, Index);
n_columns++;
Index.Column = n_columns;
Index.Row = 0;
dict_sensorM.Add(SensorT.Trigger2, Index);
n_columns++;
}
if (SensorC.acc)
{
ListIndex Index = new ListIndex();
Index.Column = n_columns;
Index.Row = 0;
dict_sensorM.Add(SensorT.ACC, Index);
n_columns++;
}
_dict_sensorN.Add(SensorC.sensorNumber, dict_sensorM);
}
//Initialize the array
_values_list = new List<double[]>();
//Initialize the document
DateTime currentDate = DateTime.Now;
string fileName = "exp_" + currentDate.ToString("yyyy-dd-M--HH-mm-ss") + ".csv";
try
{
var textWriter = new StreamWriter(fileName);
csv = new CsvWriter(textWriter);
}
catch (IOException e)
{
Console.WriteLine(e.Message + "\n Cannot create file.");
return;
}
}
public void AddToBuffer(SensorPoint sp)
{
Dictionary<SensorT, ListIndex> dict_sensorM = new Dictionary<SensorT, ListIndex>();
ListIndex Index = new ListIndex();
if (_dict_sensorN.TryGetValue(sp.ID, out dict_sensorM))
{
SensorT type = ToSensorT(sp.SensorType, sp.Battery);
if(type == SensorT.Trigger1) {
if (dict_sensorM.TryGetValue(type, out Index))
{
if (_current_max_Count < Index.Row)
{
_current_max_Count = Index.Row + 1;
_values_list[Index.Row] = new double[n_columns];
}
_values_list[Index.Row][Index.Column] =sp.Trigger1_int;
Index.Row++;
}
if (dict_sensorM.TryGetValue(SensorT.Trigger2, out Index))
{
if (_current_max_Count < Index.Row)
{
_current_max_Count = Index.Row + 1;
_values_list[Index.Row] = new double[n_columns];
}
_values_list[Index.Row][Index.Column] = sp.Trigger2_int_pos;
Index.Row++;
}
}
else {
if (dict_sensorM.TryGetValue(type, out Index))
{
if (_current_max_Count < Index.Row)
{
_current_max_Count = Index.Row;
_values_list.Add(new double[n_columns]);
}
_values_list[Index.Row][Index.Column] = sp.YPoint;
Index.Row++;
}
}
}
if (_current_max_Count > _max_Count) AddToFile();
}
private void AddToFile() {
csv.WriteRecords(_values_list);
}
private SensorT ToSensorT(SensorType stype, int battery)
{
if (stype == SensorType.EMG)
{
return SensorT.EMG;
}
else if (stype == SensorType.EMG_Trigger )
{
if (battery < 0) return SensorT.Trigger1;
else return SensorT.EMG;
}
else if (stype == SensorType.ACC)
{
return SensorT.ACC;
}
else {
return SensorT.Unknown;
}
}
}
/// <summary>
/// In order to create a multivalue dictionary it is necessary another class
/// </summary>
class ListIndex {
public int Column { get; set; }
public int Row { get; set; }
}
}

How to remove array element from user entered array

HI I'm creating a menu driven program that holds three arrays: one for the person's last name, one for the points scored and one for the player number. I made a deletemethod and deleteplayer method that is suppose to when the user enters a players number delete the player number, last name and points from the user entered list but when I use the delete method it clears the entire list. I am not sure on on how to fix this. I also have to keep the program in the main class.
Any Help would be appreciated please and thank you
static void ProcessDelete( Int32[] playerNumbers, ref Int32 playerCount, String[] playerLastName, Int32[] playerPoints)
{
Int32[] newArray = new Int32[playerNumbers.Length]; String[] newArray2 = new String[playerLastName.Length]; Int32[] newArray3 = new Int32[playerPoints.Length];
int index = Array.IndexOf(playerNumbers, 0);
{
for (int i = 0; i < playerNumbers.Length; i++)
playerNumbers[i] = 0;
}
// String[] playerLastName = new String[] { null, null, null };
for (int i = 0; index < playerLastName.Length; index++)
playerLastName[i] = " ";
for (int i = 0; i < 10; i++)
{
//Console.WriteLine(newArray2[i]);
}
for (int i = 0; i < playerPoints.Length; i++)
playerPoints[i] = 0;
}
static void DeletePlayer(Int32[] playerNumbers, String[] playerLastName, Int32[] playerPoints, ref Int32 playerCount, Int32 MAXPLAYERS)
{
int player;// Player number to delete
int playerindex;//index of the player number in Array
if (playerCount < MAXPLAYERS)
{
player = GetPositiveInteger("\nDelete Player: please enter the player's number");
playerindex = GetPlayerIndex(player, playerNumbers, playerCount);
if (playerindex != -1)
{
{
Console.WriteLine("\nDelete Player: Number - {0}, Name - {1}, Points - {2}", playerNumbers[playerindex], playerLastName[playerindex], playerPoints[playerindex]);
Console.WriteLine("Succesfully Deleted");
Console.WriteLine();
ProcessDelete( playerNumbers, ref playerCount, playerLastName, playerPoints);
}
}
else
Console.WriteLine("\nDelete Player: player not found");
}
else
Console.WriteLine("\nDelete Player: the roster is empty");
}
}
}
In an object-oriented language, you would generally create a class to capture this information.
Let me know if you need any explanation because, as always, there's more than one way to do this.
Updated with CurrentScore, AddPlayerToGame() function, and incrementing playercount
class Program {
static void Main(string[] args) {
//Create firstPlayer
Player firstPlayer = new Player {
PlayerId = 1,
DisplayName = "Goober",
LastName = "Smith"
};
// Create secondPlayer
Player secondPlayer = new Player {
PlayerId = 2,
DisplayName = "Destructor",
LastName = "Henry"
};
// Create game instance
Game currentGame = new Game();
// Add players to game
currentGame.AddPlayerToGame(firstPlayer);
currentGame.AddPlayerToGame(secondPlayer);
// Player scores a point
secondPlayer.CurrentScore++;
// Player clicks LeaveGame, etc.
currentGame.PlayerLeavesGame(firstPlayer);
}
}
public class Player {
public int PlayerId { get; set; } // I assume the same as player numbers
public string DisplayName { get; set; }
public string LastName { get; set; }
public int CurrentScore { get; set; }
}
public class Game {
private static readonly int MAXPLAYERS = 10;
public Game() {
Players = new List<Player>();
}
public List<Player> Players { get; private set; }
private int _PlayerCount = 0;
public int PlayerCount {
get {
return _PlayerCount;
}
set {
_PlayerCount = value;
}
}
/// <summary>
/// Tries to add a player to the game
/// </summary>
/// <param name="playerThatJoinedGame"></param>
/// <returns>True if the player was added and the game wasn't full</returns>
public bool AddPlayerToGame(Player playerThatJoinedGame) {
if (PlayerCount < MAXPLAYERS) {
Players.Add(playerThatJoinedGame);
PlayerCount++;
return true;
}
else {
return false;
}
}
/// <summary>
/// Removes a player from the game
/// </summary>
/// <param name="playerThatQuit">The leaving player</param>
public void PlayerLeavesGame(Player playerThatQuit) {
// Removes the player from the game
Players.Remove(playerThatQuit);
PlayerCount--;
}
}
If all the information in the lists is logically related why aren't you using Lists or Dictionaries?
Something like this:
using System.Collections.Generic;
class Player{
public int Number;
public string LastName;
public int Points;
}
class PlayerManager{
static Dictionary<int,Player> dctOfPlayers= new Dictionary<int, Player>();
public static AddNewPlayer(Player newPlayer){
dctOfPlayers.Add(newPlayer.Number,newPlayer);
}
public static RemovePlayer(int playerNumber){
dctOfPlayers.Remove(playerNumber);
}
}
You could use a list of Players and make loops to find the user ID too...
Also if for any reason you want to preserve the Player entry and just reset the information then you can:
using System.Collections.Generic;
class Player{
public int Number;
public string LastName;
public int Points;
public ResetInfo(){
Number=0;
LastName="";
Points=0;
}
}
class PlayerManager{
static Dictionary<int,Player> dctOfPlayers= new Dictionary<int, Player>();
public static AddNewPlayer(Player newPlayer){
dctOfPlayers.Add(newPlayer.Number,newPlayer);
}
public static RemovePlayer(int playerNumber){
dctOfPlayers[layerNumber].ResetInfo();
}
}

Categories