Elements in list are getting overwritten when adding to list - c#

I'm reading in tags and values from an XML file for information that is needed for a functional test software. When adding the Frequencies to the list, the frequencies for all other existing list items are overwritten by the new frequencies.
public struct Configuration
{
public string Description;
public byte Mode;
public byte Deviation;
public string PartNumber;
public UInt16[] Frequencies;
public byte TxPower;
public byte PWM;
public Int16 HeaterSetpoint;
public string FirmwareVersion;
public bool Active;
public int Threshold;
} // struct Configuration
Configurations = new List<Configuration>();
ushort[] Frequencies = new ushort [7];
Configuration TestConfig = new Configuration();
/*Open the XML file, load all the tag values into XmlNodeList */
//Pull in all the XML Tag Values Sorted by Tag Name
XmlNodeList xml_description = ConfigFile.GetElementsByTagName("description");
XmlNodeList xml_mode = ConfigFile.GetElementsByTagName("mode");
XmlNodeList xml_deviation = ConfigFile.GetElementsByTagName("deviation");
XmlNodeList xml_partnumber = ConfigFile.GetElementsByTagName("partnumber");
XmlNodeList xml_channel0 = ConfigFile.GetElementsByTagName("channel0");
XmlNodeList xml_channel1 = ConfigFile.GetElementsByTagName("channel1");
XmlNodeList xml_channel2 = ConfigFile.GetElementsByTagName("channel2");
XmlNodeList xml_channel3 = ConfigFile.GetElementsByTagName("channel3");
XmlNodeList xml_channel4 = ConfigFile.GetElementsByTagName("channel4");
XmlNodeList xml_channel5 = ConfigFile.GetElementsByTagName("channel5");
XmlNodeList xml_channel6 = ConfigFile.GetElementsByTagName("channel6");
XmlNodeList xml_txpower = ConfigFile.GetElementsByTagName("txpower");
XmlNodeList xml_pwm = ConfigFile.GetElementsByTagName("pwm");
XmlNodeList xml_hsp = ConfigFile.GetElementsByTagName("hsp");
XmlNodeList xml_firmware = ConfigFile.GetElementsByTagName("firmware");
XmlNodeList xml_active = ConfigFile.GetElementsByTagName("active");
XmlNodeList xml_threshold = ConfigFile.GetElementsByTagName("threshold");
/*Use LINQ to check that the XmlNodeLists are all the same length. This way we don't try and load invalid data*/
if(!listsaresamelength)
{
/*Alert user there is a problem with the XML file and close the application*/
}
//Loop to add values to the List
for(i = 0; i < NumberofXmlValues; i++)
{
/*check that the description, Mode, Deviation are valid and add them to DummyConfig*/
try
{
Frequencies[0] = UInt16.Parse(xml_channel0[i].InnerText);
Frequencies[1] = UInt16.Parse(xml_channel1[i].InnerText);
Frequencies[2] = UInt16.Parse(xml_channel2[i].InnerText);
Frequencies[3] = UInt16.Parse(xml_channel3[i].InnerText);
Frequencies[4] = UInt16.Parse(xml_channel4[i].InnerText);
Frequencies[5] = UInt16.Parse(xml_channel5[i].InnerText);
Frequencies[6] = UInt16.Parse(xml_channel6[i].InnerText);
//Move the frequencies to the list
TestConfig.Frequencies = Frequencies;
}
catch
{
/*Problem with the XML file. Alert the user and close the application*/
}
/*check that the heater set point, PWM set point, partnumber, Txpower, and Threshold are valid and add them to DummyConfig*/
Configurations.Add(TestConfig)
}
The first iteration of the for loop works fine; here's the result:
first loop iteration
second loop iteration
I've tried a few different ways to change how I'm writing to the list, but they all generate the same result. I feel like I'm missing something obvious.

You need to move your TestConfig and Frequencies variables' instantiation into the for loop so that you're working with a different object each time.
for(i = 0; i < NumberofXmlValues; i++)
{
TestConfig = new Configuration();
Frequencies = new ushort [7];
I'd personally recommend making these locally-declared variables rather than persistent fields. That pattern will help you avoid mistakes like this in the future.
for(i = 0; i < NumberofXmlValues; i++)
{
/*check that the description, Mode, Deviation are valid*/
...
try
{
var testConfig = new Config
{
Description = description
...
Frequencies = new [] {xml_channel0, xml_channel1, ...}
.Select(c => UInt16.Parse(c[i].InnerText))
.ToArray()
};
Configurations.Add(testConfig);
}
...

Related

Resetting the order in schedules

The goal of this macros (app) is to reset the order of elements inside of a schedule we have opened now. Order starts with a user chosen number. Numbers are stored inside every element's parameter that user can specify. We get IDs of elements by hitting "IDs of Selection".
Resetting the order
public void AutoNumerate()
{
Document doc = this.ActiveUIDocument.Document;
ViewSchedule vs = doc.ActiveView as ViewSchedule;
TableData tData = vs.GetTableData();
TableSectionData tsDada = tData.GetSectionData(SectionType.Body);
int startIndex = 1; //SETTING STARTING NUMBER
using (TransactionGroup tGroup = new TransactionGroup(doc,"Numeration: "+vs.Name))
{
tGroup.Start();
for (int rInd = 0; rInd < tsDada.NumberOfRows; rInd++)
{
SetNum(doc,startIndex++, );
}
tGroup.Assimilate();
}
}
public void SetNum(Document doc, int num, List<Element> Myelements)
{
using (Transaction tr = new Transaction(doc,"Creating elements based on IDs"))
{
tr.Start();
//List<ElementId> eleIds = new List<ElementId>{946164,946385,946484,946631,946708,946759,946816};
int[] eleIds = {946164,946385,946484,946631,946708,946759,946816};
foreach (int id in eleIds)
{
List<Element> MyElements = GetElement();
}
foreach (Element ele in MyElements)
{
//ele.LookupParameter("Comments").Set(num.ToString());
ele.LookupParameter("Comments").Set(num.ToString()).ToList(); //SPECIFYING PARAMETER
}
tr.Commit();
}
}
private List<Element> GetElementsOnRow(Document doc, ViewSchedule vs, int rowNumber)
{
TableData tableData = vs.GetTableData();
TableSectionData tableSectionData = tableData.GetSectionData(SectionType.Body);
To sort a schedule you need to use the ScheduleDefinition.AddSortGroupField method. Create a ScheduleSortGroupField from the ScheduleFieldId of the 'Comments' parameter to input into the method.

How can I access multi-element List data stored in a public class?

My first question on SO:
I created this public class, so that I can store three elements in a list:
public class myMultiElementList
{
public string Role {get;set;}
public string Country {get;set;}
public int Commonality {get;set;}
}
In my main class, I then created a new list using this process:
var EmployeeRolesCountry = new List<myMultiElementList>();
var rc1 = new myMultiElementList();
rc1.Role = token.Trim();
rc1.Country = country.Trim();
rc1.Commonality = 1;
EmployeeRolesCountry.Add(rc1);
I've added data to EmployeeRolesCountry and have validated that has 472 lines. However, when I try to retrieve it as below, my ForEach loop only retrieves the final line added to the list, 472 times...
foreach (myMultiElementList tmpClass in EmployeeRolesCountry)
{
string d1Value = tmpClass.Role;
Console.WriteLine(d1Value);
string d2Value = tmpClass.Role;
Console.WriteLine(d2Value);
int d3Value = tmpClass.Commonality;
Console.WriteLine(d3Value);
}
This was the most promising of the potential solutions I found on here, so any pointers greatly appreciated.
EDIT: adding data to EmployeeRolesCountry
/*
Before this starts, data is taken in via a csvReader function and parsed
All of the process below is concerned with two fields in the csv
One is simply the Country. No processing necessary
The other is bio, and this itself needs to be parsed and cleansed several times to take roles out
To keep things making sense, I've taken much of the cleansing out
*/
private void File_upload_Click(object sender, EventArgs e)
{
int pos = 0;
var EmployeeRolesCountry = new List<myMultiElementList>();
var rc1 = new myMultiElementList();
int a = 0;
delimiter = ".";
string token;
foreach (var line in records.Take(100))
{
var fields = line.ToList();
string bio = fields[5];
string country = fields[4];
int role_count = Regex.Matches(bio, delimiter).Count;
a = bio.Length;
for (var i = 0; i < role_count; i++)
{
//here I take first role, by parsing on delimiter, then push back EmployeeRolesCountry with result
pos = bio.IndexOf('.');
if (pos != -1)
{
token = bio.Substring(0, pos);
string original_token = token;
rc1.Role = token.Trim();
rc1.Country = country.Trim();
rc1.Commonality = 1;
EmployeeRolesCountry.Add(rc1);
a = original_token.Length;
bio = bio.Remove(0, a + 1);
}
}
}
}
EDIT:
When grouped by multiple properties, this is how we iterate through the grouped items:
var employeesGroupedByRolwAndCountry = EmployeeRolesCountry.GroupBy(x => new { x.Role, x.Country });
employeesGroupedByRolwAndCountry.ToList().ForEach
(
(countryAndRole) =>
{
Console.WriteLine("Group {0}/{1}", countryAndRole.Key.Country, countryAndRole.Key.Role);
countryAndRole.ToList().ForEach
(
(multiElement) => Console.WriteLine(" : {0}", multiElement.Commonality)
);
}
);
__ ORIGINAL POST __
You are instantiating rc1 only once (outside the loop) and add the same instance to the list.
Please make sure that you do
var rc1 = new myMultiElementList();
inside the loop where you are adding the elements, and not outside.
All references are the same in your case:
var obj = new myObj();
for(i = 0; i < 5; i++)
{
obj.Prop1 = "Prop" + i;
list.Add(obj);
}
now the list has 5 elements, all pointing to the obj (the same instance, the same object in memory), and when you do
obj.Prop1 = "Prop" + 5
you update the same memory address, and all the pointers in the list points to the same instance so, you are not getting 472 copies of the LAST item, but getting the same instance 472 times.
The solution is simple. Create a new instance every time you add to your list:
for(i = 0; i < 5; i++)
{
var obj = new myObj();
obj.Prop1 = "Prop" + i;
list.Add(obj);
}
Hope this helps.

Objects in list get removed when applying Dijkstra's Algorithm implementation

I didn't know how to formulate the question title any better without getting too descriptive, I'm sorry in advance...
Anyhow, my problem is the following.
I have a List NodeList, and a secondary List named Unvisited.
I use the Method GetPath on the Unvisited list (it's an implementation of Dijkstra's Pathfidning Algorithm). But for some weird reason when I draw the texture stored in the Nodes in the NodeList some of the nodes (particularly, the nodes used to trace a path between) get removed.
I am looking for an explanation why the Nodes get removed from the NodeList even when I clearly set Unvisited equal NodeList...
EDIT: If there is any code that is missing to understand the problem, ask and I will edit!
Relevant Code:
public class Hotel
{
public List<Node> nodeList;
//constructor loadscontent and initialises list, ommitted here.
public void BuildHotel(ContentManager content)
{
for (int i = 0; i < 5; i++)
{
GuestRoom temp = new GuestRoom(100 + i, content, new Point(64 + (i * 64), 128), new Point(2, 1));
nodeList.Add(new Node(temp, new Point(64 + (i * 64), 128)));
}
// add edges between some nodes
for (int i = 0; i < 4; i++)
{
AddEdge(nodeList[i].Room.RoomId, nodeList[i + 1].Room.RoomId, 2);
}
guest = new Guest(content);
guest.Setpath(100, 104, nodeList);
}
}
class PathFinding
{
public List<Node> Unvisited;
public List<Node> Visited;
private Stack<Node> _temp = new Stack<Node>();
public Stack<Node> GetPath(int startroom, int finalroom, List<Node> nodeList)
{
Unvisited = nodeList;
Node startNode = Unvisited.DefaultIfEmpty(null).FirstOrDefault(x => x.Room.RoomId == startroom);
Node finalNode = Unvisited.DefaultIfEmpty(null).FirstOrDefault(x => x.Room.RoomId == finalroom);
if (startNode == null || finalNode == null)
{
Console.WriteLine("At least one of the nodes does not exist");
return null;
}
startNode.Distance = 0;
Node currentNode = startNode;
while (!IsVisited(currentNode, finalNode))
{
currentNode = Unvisited.Aggregate((l, r) => l.Distance < r.Distance ? l : r);
}
//reverse nodes in queue
Queue<Node> reversedqueue = MakePath(startNode, currentNode, finalNode);
for (int i = 0; i < MakePath(startNode, currentNode, finalNode).Count; i++)
{
_temp.Push(reversedqueue.Dequeue());
}
return _temp;
}
}
public class SimulationScreen : Screen
{
private Hotel hotel;
//.. other methods ommited.
public override void Activate(bool instancePreserved)
{
if (!instancePreserved)
{
if (_content == null)
_content = new ContentManager(ScreenManager.Game.Services, "Content");
ScreenManager.Game.ResetElapsedTime();
}
hotel = new Hotel(_content);
}
}
Visual Representation on the bug
Without the pathfinder turned on
Your problem is right here:
Unvisited = nodeList;
That's the problem, I have looked through my entire solution and there is not a single place where the nodes get removed from the NodeList ._. any removal from the list is from the Unvisited list... :s
After that assignment, any removal from the Unvisited list removes from the nodeList. List is a reference type, so when you change its value with an assignment you're really changing which object it refers to. Unvisited and nodeList both refer to the same object after this. To avoid this, instantiate a new List using the old one rather than assigning both lists to the same reference:
Unvisited = new List<Node>(nodeList);

Trying to Create an array holding a Struct?

I am trying to have an Array hold a Struct with two elements, to Hold a Xml Tag name and its value.
I would like to have the array working like this:
MyArrayStruct[Count].TagName = "Bla Bla";
MyArrayStruct[Count].TagValue = "Bla Bla Bla";
Could some please help me to get this working.
public struct TagContents
{
String TagName;
String TagValue;
};
I am having problems with declaring the Array as Struct to have it working like i want, i what it to be working like the comment out code.
public void LoadXML()
{
if (File.Exists("Data.xml"))
{
//Readin XML
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("Data.xml");
XmlNodeList dataNodes = xmlDoc.SelectNodes("//FieldData");
//Count the nodes
int Max = 0;
foreach (XmlNode node in dataNodes)
{
Max = Max + 1;
}
int Count = 0;
//TagContents MyXmlPointer = new TagContents();
// MyXmlPointer[] ArrayNode;
// ArrayNode = new MyXmlPointer[Max];
foreach (XmlNode node in dataNodes)
{
// ArrayNode[Count].TagName =node.SelectSingleNode("Have not found what to put here yet but will get there").Name;
// ArrayNode[Count].TagValue =node.SelectSingleNode("Have not found what to put here yet but will get there").InnerText;
}
}
else
{
MessageBox.Show("Could not find file Data.xml");
}
}
Make fields public:
public class TagContent
{
public String TagName;
public String TagValue;
};
and use it, I suggest use generics (Like List<>):
var tags = new List<TagContent>();
tags.Add(new TagContent{TagName = "aaa", TagValue = "vvv"});
// use it:
// get value of 'TagName' of item 5:
var tagname5 = tags[5].TagName;

Using LINQ to find three or more matching records

First, I'll describe my table structure.
I have table, with 2 columns (ID and Root). This table is converted to a List of Nodes where the simple node structure is:
struct Node
{
public int id;
public int root;
}
I need to find all entries in this List where there's 3 or more roots equals.
Example:
struct TeleDBData
{
public int ID;
public int? RootID;
}
private void InitList()
{
var eqList = new List<TeleDBData>();
TeleDBData root = new TeleDBData();
root.ID = 1;
TeleDBData node1 = new TeleDBData();
node1.ID = 2;
node1.RootID = 1;
TeleDBData node2 = new TeleDBData();
node2.ID = 3;
node2.RootID = 1;
TeleDBData node3 = new TeleDBData();
node3.ID = 4;
node3.RootID = 1;
TeleDBData node4 = new TeleDBData();
node4.ID = 5;
node4.RootID = 2;
eqList.Add(root);
eqList.Add(node1);
eqList.Add(node2);
eqList.Add(node3);
eqList.Add(node4);
}
After running the query, it will return node1, node2 and node3.
How can I find them using LINQ?
You just need to GroupBy accordingly:
var groups = eqList.GroupBy(n => n.RootID).Where(g => g.Count() >= 3);
foreach (var g in groups) {
Console.Out.WriteLine("There are {0} nodes which share RootId = {1}",
g.Count(), g.Key);
foreach (var node in g) {
Console.Out.WriteLine(" node id = " + node.ID);
}
}
See it in action.
Additional info:
In the code above, g is an IGrouping<int?, TeleDBData> so, by the documentation page definition, it's a collection of TeleDBData items that share a common key (which is an int?). groups is an IEnumerable<IGrouping<int?, TeleDBData>>, all of this is standard procedure for the Enumerable.GroupBy method.
The two things you would want to do with an IGrouping<,> is access its Key property to find the key and enumerate over it to process the grouped elements. We 're doing both of this in the above code.
As for the n in the GroupBy lambda, it simply represents each one of the items in eqList in turn; it follows that its type is TeleDBData. I picked n as the parameter name as an abbreviation of "node".

Categories