I am creating an applicaiton that requires the use of recursive aggregation in one of the classes. The class at hand is entitiled "component" and a component may be made up of sub components stored within a list. The following code shows this.
public class Component {
//vars for class
public String componentName;
public String componentShape;
public String componentColour;
public String componentMaterial;
public int numChildComps;
//list to store child components of component
public List<Component> childComponents;
public Component(string _componentName, string _componentShape, string _componentColour, string _componentMaterial, int _numChildComps)
{
componentName = _componentName;
componentShape = _componentShape;
componentColour = _componentColour;
componentMaterial = _componentMaterial;
numChildComps = _numChildComps;
//if component has no child components set list to null
if (numChildComps == 0)
{
//instatiate new list
childComponents = new List<Component>();
childComponents = null;
}
else if(numChildComps != 0)//if not null then create child components for the amount stated above.
{
childComponents = new List<Component>();
for (int i = 0; i < numChildComps; i++)
{
Console.WriteLine("Add details for child component " + (i+1));
Console.WriteLine("Enter component Name: ");
string name = Console.ReadLine();
Console.WriteLine("Enter shape: ");
string shape = Console.ReadLine();
Console.WriteLine("Enter Colour: ");
string colour = Console.ReadLine();
Console.WriteLine("Enter Material: ");
string material = Console.ReadLine();
Console.WriteLine("Enter num child components: ");
string num = Console.ReadLine();
childComponents.Add(new Component(name, shape, colour, material, Int16.Parse(num)));//instatiate new child component with params and add to the list.
}
}
}
This will instaiated a class and if the parameter for number fo child components is more than 0 then it will create the object and store it in the list "childComponents". This works fine. My question is how would I go about retrieving the items within the list. Take the following as an example, I have a model which is made up of one component but that component has 2 components and one of those has another 2 and one of those has one component:
Model
-component
-childComponent
-childComponent
-childComponent
-childComponent
-childComponent
Obviously this could go on forever and I have tried creating a piece of code to retireve all the components and sub components but it has not worked as you need to know the total amount of components a model has and then that components childComponents and so on.
Code that I have tried(does not model the above example)
IEnumerable<SEModel> modelres = from SEModel sm in database
select sm;
foreach (SEModel item in modelres)
{
Console.WriteLine(item.getSetModelName);
Console.WriteLine(item.componentList.First().componentName);
foreach (SEComponent citem in item.componentList)
{
Console.WriteLine(citem.childComponents.First().componentName);
foreach (SEComponent scitem in citem.childComponents)
{
Console.WriteLine(scitem.componentName);
}
}
Like stated above you would have to know the amount of components with childcomponents and then their childcomponents and so on.
public IEnumerable<Component> GetComponents()
{
yield return this;
foreach( var childComp in childComponents )
{
foreach( var comp in childComp.GetComponents() )
{
yield return comp;
}
}
}
If you're not sure what yield return is all about, read this
If you need to retrieve the components as a flat list you can do it this way:
public List<Component> GetAllComponents(List<Component> components)
{
var result = new List<Component>();
result.AddRange(components);
foreach (var component in components)
result.AddRange(GetAllComponents(component.childComponents));
return result;
}
var allComponents = GetAllComponents(Model.Components);
Though I am not sure from your question what exactly you want to do.
Related
I have to create a function that enables me to enter data for every customer in a hardware store. The data that I should enter for every customer is: first name, last name, product bought and its price. This data should be stored in an array. Have this function declare a 1D container, have the user initialise this 1D container with the above data, and have the function return this 1D container back to MAIN. In MAIN, invoke this function three times to create data for 3 customers.
Afterwards, I need to create another function that takes all three 1D containers of customer data from MAIN as parameters and adds up all the prices of the products they bought. Have this function return the total cost back to MAIN. (This is where I'm stuck.)
Lastly, I need to create a procedure that takes the total cost returned to MAIN as parameter and figures out if this total price(set to a simple integer) is a prime number:
if the value is prime, print: "Customers win the Price"
otherwise, print: "Customers won't get the price"
I am stuck on the second function, I tried to do a C-style for loop, but it doesn't work.
I tried to add these three prices as array positions with indices but nothing.
This is the code I have:
using System;
namespace ghghh
{
class Program
{
public static string [] inputData()
{
Console.WriteLine("Please enter your first name: ");
string FirstName = Console.ReadLine();
Console.WriteLine("Please enter your last name: ");
string LastName = Console.ReadLine();
Console.WriteLine("Please enter the product you ahve bought: ");
string product = Console.ReadLine();
Console.WriteLine("Please enter the price: ");
string price = Console.ReadLine();
string[] info = new string[4] { FirstName, LastName, product, price };
return info;
}
public static void sumOfPrice(string[] arr)
{
for(int i = 0; i<arr.Length; i++)
{
string sum = arr[i] + arr[i] + arr[i];
}
}
public static void isTotalCostPrime(int n)
{
if(n %2 == 0)
{
Console.WriteLine("Customers wont get get the prize.");
}
else
{
Console.WriteLine("Customers win the prize");
}
}
public static void Main (string[] args)
{
string[] final = inputData();
sumOfPrice(final);
}
}
}
Here you go with a partial solution to your problem. I made the prices decimal numbers (because most currencies are decimalized). That precludes your prime test at the end.
I also included a quantity. I was tempted to take out the first and last names for each item (since it requires a lot of typing). All in all, though, this should give you enough to get started.
I start with a POCO class to hold the purchased items (POCO stands for "Plain Old CLR Object"; it's a class that consists purely of properties. It's a bit like an old-fashioned C struct.
public class PurchasedItem
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string ProductName { get; set; }
public int Quantity { get; set; }
public decimal Price { get; set; }
}
I separated the user interface out into a separate class (for reasons of separation of concerns). You could easily collapse this into a single class:
public class ItemUserInterface
{
public static PurchasedItem PromptForItem()
{
var purchasedItem = new PurchasedItem();
Console.Write("What is your First Name (or type \"exit\" if complete)? > ");
var firstName = Console.ReadLine();
if (firstName.Equals("exit", StringComparison.OrdinalIgnoreCase))
{
return null;
}
purchasedItem.FirstName = firstName;
Console.Write("What is your Last Name? > ");
purchasedItem.LastName = Console.ReadLine();
Console.Write("What did you purchase? > ");
purchasedItem.ProductName = Console.ReadLine();
purchasedItem.Quantity = PromptForInteger("How many did you buy");
purchasedItem.Price = PromptForDecimal("What was the price");
Console.WriteLine(""); //empty line
return purchasedItem;
}
public static void ShowPurchase (PurchasedItem item)
{
Console.WriteLine($"{item.FirstName} {item.LastName} bought {item.Quantity} of {item.ProductName} at {item.Price} each");
}
public static int PromptForInteger(string prompt)
{
while (true)
{
Console.Write(prompt + " > ");
var entered = Console.ReadLine();
if (int.TryParse(entered, out var result))
{
return result;
}
//otherwise error
Console.WriteLine("Sorry, you must enter a proper integer value");
}
}
public static decimal PromptForDecimal(string prompt)
{
while (true)
{
Console.Write(prompt + " > ");
var entered = Console.ReadLine();
if (decimal.TryParse(entered, out var result))
{
return result;
}
//otherwise error
Console.WriteLine("Sorry, you must enter a proper decimal value");
}
}
}
By the way, while (true) will loop forever unless you do something like return or break out of the loop. Notice that I prompt the user over and over again until he/she enters a correctly formatted number (for the number entries).
Finally, here's my Main routine:
var itemsList = new List<PurchasedItem>();
while (true)
{
var item = ItemUserInterface.PromptForItem();
if (item == null)
{
break;
}
itemsList.Add(item);
}
// at this point, everything is entered
var totalPurchasePrice = 0.00m;
var totalItemsCount = 0;
foreach (var item in itemsList)
{
ItemUserInterface.ShowPurchase(item);
totalPurchasePrice += (item.Quantity * item.Price);
totalItemsCount += item.Quantity;
}
Console.WriteLine($"Purchase Summary: {itemsList.Count} different items ({totalItemsCount} total items) for {totalPurchasePrice:C}");
Console.ReadLine(); //pause
}
If I run this program the output looks like:
What is your First Name (or type "exit" if complete)? > Fly
What is your Last Name? > Dog57
What did you purchase? > Cabbage
How many did you buy > 2
What was the price > 1.99
What is your First Name (or type "exit" if complete)? > Fly
What is your Last Name? > Dog57
What did you purchase? > Hammer
How many did you buy > 6
What was the price > abc
Sorry, you must enter a proper decimal value
What was the price > 10.55
What is your First Name (or type "exit" if complete)? > exit
Fly Dog57 bought 2 of Cabbage at 1.99 each
Fly Dog57 bought 6 of Hammer at 10.55 each
Purchase Summary: 2 different items (8 total items) for $67.28
I am trying to process a list of addresses into 2 collections; a list of addresses that meets requirements; a list of scores for each of those addresses that meets requirements.
I have several different criteria to slice and dice the addresses, but I am running into an incorrect implementation of modifying a collection during parallel processing.
For instance, I take the zip code and for each (+388k records) I determine if the Levenshtein Distance is greater or equal to a filtering value. If it does, then add the address to the compiled list of addresses. Then using the SET method, determine if the score for the address already exists. If is does not, then add. Else use the score currently in the collection and update the appropriate property.
I am hitting the "Collection Has Been Modified" error and I can not think of another way to implement the solution. I am looking for alternative ways to accomplish this.
private LevenshteinDistance _ld = new LevenshteinDistance();
private int _filter_zip = int.Parse(ConfigHelper.GetAppSettingByKey("filter_zip"));
public Factory ScoreAddresses(Factory model)
{
Factory result = model;
IList<Address> _compiledList = new List<Address>();
IList<Scores> _compiledScores = new List<Scores>();
ParallelLoopResult MailLoopResult = Parallel.ForEach(
result.ALL_Addresses, factory =>
{
if (factory.MAIL_ZIP_CODE_NBR != null
&& factory.MAIL_ZIP_CODE_NBR.Length >= 1)
{
int _zipDistance = _ld.Compute(
result.Target_Address.MAIL_ZIP_CODE_NBR,
factory.MAIL_ZIP_CODE_NBR);
if (_zipDistance <= _filter_zip)
{
_compiledList.Add(factory);
Scores _score = new Scores();
_compiledScores = _score.Set(_compiledScores,
factory.INDIVIDUAL_ID, "Levenshtein_MAIL_ZIP_CODE_NBR",
_zipDistance, string.Empty, null);
}
}
});
return result;
}
public IList<Scores> Set(IList<Scores> current, int Individual_ID,
string Score_Type, int Levenshtein, string Methaphone, decimal? other)
{
int currentcount = current.Count();
bool updating = false;
IList<Scores> result = current;
try
{
Scores newscore = new Scores();
//Check if scoreing for individual already present
Scores lookingforIndv = current.AsParallel().Where(
p => p.INDIVIDUAL_ID == Individual_ID).FirstOrDefault();
if (lookingforIndv != null)
{
newscore = lookingforIndv;
updating = true;
}
else
{
newscore.INDIVIDUAL_ID = Individual_ID;
updating = false;
}
//Add score based upon indicated score type
switch (Score_Type)
{
case "Levenshtein_MAIL_ZIP_CODE_NBR":
newscore.Levenshtein_MAIL_ZIP_CODE_NBR = Levenshtein;
result.Add(newscore);
break;
//More and More Cases
}
}
catch (Exception e)
{
}
return result;
}
I have this class:
class player
{
public string name;
public int rating;
{
The number of these classes made is dependant on a user specified amount numberOfPlayers. So my first reaction was to create a for loop to do this. i.e:
for (int i = 0; i< numberOfPlayers; i++)
{
//create class here
}
However, I need to be able to access these classes individually when later using their individual data - almost like they've been put into an array. How would I go about making a number of classes of which can be accessed individually?
You use a List<T> variable where T is your class
List<Player> players = new List<Player>();
for (int i = 0; i< numberOfPlayers; i++)
{
Player p = new Player();
p.Name = GetName();
p.rating = GetRating();
players.Add(p);
}
Of course GetName and GetRating should be substituded by your code that retrieves these informations and add them to the single player.
Getting data out of a List<T> is in no way very different from reading from an array
if(players.Count > 0)
{
Player pAtIndex0 = players[0];
....
}
You can read more info at MSDN page on List class
List<Player> players = new List<Player>();
for (int i = 0; i< numberOfPlayers; i++)
{
Player p = new Player();
p.Name = "";
p.rating = "";
players.Add(p);
}
to access it individually you can use...
foreach(Player p in players )
{
}
You've got the right idea. Make a player class that can be re-used over and over, a loop in which to create these players and now we need to store them somewhere. This will probably divide opinion if you get more than one answer but I like dictionaries for this kind of thing as you can access values by unique keys.
// Your player class. I've added 'id' so we can identify them by this later.
class Player
{
public int id;
public string name;
public int rating;
}
// The dictionary. They work like this dictionary<key, value> where key is a unique identifier used to access the stored value.
// Useful since you wanted array type accessibility
// So in our case int represents the player ID, the value is the player themselves
Dictionary<int, Player> players = new Dictionary<int, Player>();
// Create your players
for (int i = 0; i < numberOfPlayers; i++)
{
Player p = new Player()
{
id = i + 1,
name = $"Player{i}",
rating = 5
};
// Add them to dictionary
players.Add(p.id, p);
}
// Now you can access them by the ID:
if (players.ContainsKey(1))
{
Console.WriteLine(players[1].name);
}
The dictionary key can be anything you like so long as it's unique. You could identify them by name if you like.
I am new in generic collections
I have one class .The class name is ReportSubCategoryModel
these are that class properties
public class ReportSubCategoryModel
{
public string ReporTitle { get; set; }
public string ReporStatus { get; set; }
public string ReportDescription { get; set; }
public int ReporSubCategoryId { get; set; }
public IList<ReportSubCategoryModel> ReportSubCategoryModelList { get; set; }
}
I want to set the lot of values in this class properties from database . So i assigned a list of that class
IList<ReportSubCategoryModel> reportSubCategoryModel = new List<ReportSubCategoryModel>();
Now I want to set a values inside of for loop
IList<ReportSubCategory> reportSubCategory = datamodel.ReportSubCategory.Where(r => r.ReportCategoryId == reportCategoryId).ToList();
for (int i = 0; i < reportSubCategory.Count; i++)
{
int reportSubCategoryId = reportSubCategory[i].ReportSubCategoryId;
ReportStatu reportStatus =
datamodel.ReportStatus.SingleOrDefault(
r => r.ReportSubCategoryId == reportSubCategoryId);
if (reportStatus == null)
{
reportSubCategoryModel[i].ReportDescription = "Dis";**//This line threw the error**
reportSubCategoryModel[i].ReporStatus = "Not Available";
reportSubCategoryModel[i].ReporTitle = reportSubCategory[i].ReportSubCategoryName;
reportSubCategoryModel[i].ReportSubCategoryModelList.Add(reportSubCategoryModel[i]);
}
else
{
reportSubCategoryModel[i].ReportDescription = "Dis";
reportSubCategoryModel[i].ReporStatus = "Available For " + reportStatus.ReportStatusDescription;
reportSubCategoryModel[i].ReporTitle = reportSubCategory[i].ReportSubCategoryName;
reportSubCategoryModel[i].ReporSubCategoryId = reportSubCategoryId;
reportSubCategoryModel[i].ReportSubCategoryModelList.Add(reportSubCategoryModel[i]);
}
}
return reportSubCategoryModel.ToList();
But it's not working.
This line reportSubCategoryModel[i].ReportDescription = "Dis"; give's the error for Index was out of range. Must be non-negative and less than the size of the collection.
You can see this problem and my code from below image.Please zoom your browser (cntrl+Up Mouse Scrolling)
how can i solve this problem ?
I'm not entirely sure what the whole logic is meant to be, but this is how I feel the code should look like:
IList<ReportSubCategory> reportSubCategory = datamodel.ReportSubCategory
.Where(r => r.ReportCategoryId == reportCategoryId)
.ToList();
foreach (var subCategory in reportSubCategory)
{
int reportSubCategoryId = subCategory.ReportSubCategoryId;
ReportStatus reportStatus = datamodel.ReportStatus
.SingleOrDefault(r => r.ReportSubCategoryId == reportSubCategoryId);
if (reportStatus == null)
{
var model = new ReportSubCategoryModel();
model.ReportDescription = "Dis";
model.ReporStatus = "Not Available";
model.ReporTitle = subCategory.ReportSubCategoryName;
// Not sure what this is.
//model.ReportSubCategoryModelList.Add(reportSubCategoryModel[i]);
reportSubCategoryModel.Add(model);
}
else
{
var model = new ReportSubCategoryModel();
model.ReportDescription = "Dis";
model.ReporStatus = "Available For " + reportStatus.ReportStatusDescription;
model.ReporTitle = subCategory.ReportSubCategoryName;
model.ReporSubCategoryId = reportSubCategoryId;
// Not sure what this is either.
//reportSubCategoryModel[i].ReportSubCategoryModelList.Add(reportSubCategoryModel[i]);
reportSubCategoryModel.Add(model);
}
}
return reportSubCategoryModel;
Basically, you new up a model, set the properties and then Add that to the model list; based on iterating the sub category list.
However, I'm not sure what the whole nested list thing is about (the code I commented out).
Also, this code can be further trimmed, but I'll leave that out for now so as not to depart too much from the provided code.
Create a nested loop with in your main loop.With reportSubCategoryModel.Count.
you are treating list as an array.
something similar to following could replace the assigning section
var temp = new ReportSubCategoryModel();
temp.ReportDescription = "dis";
....
reportSubCategoryModel.Add(temp);
should sort the issue.
As far as I can see you have only created the list of reportSubCategoryModel and not yet populated it.
A list does not pre-populate with empty values and will therefore have a length of zero after initialisation. If you with to add new values you need to create your ReportSubCategoryModel object and then add it to the List.
Instead of trying to edit the values of the list;
reportSubCategoryModel[i].ReportDescription = "Dis";
Create the ReportSubCategoryModel object first, fill the data and the use the List.Add method to add it to your List.
ReportSubCategoryModel reportSubCategoryModelObject = new ReportSubCategoryModel();
reportSubCategoryModelObject.ReportDescription = "Dis";**//This line threw the error**
reportSubCategoryModelObject.ReporStatus = "Not Available";
reportSubCategoryModelObject.ReporTitle = reportSubCategory[i].ReportSubCategoryName;
reportSubCategoryModel.Add(reportSubCategoryModelObject);
I have written a simple method that receives a Generic that I wish to place into an ArrayList using the ArrayList.Add() method. However I have discovered that when I go add a new item with the same type as previous items in the ArrayList this new item overwrites the previous items individual properties.
Here's the code its pretty basic and rather embarrassingly I can't seem to rectify this overwriting problem.
public class ChromosomeTree<T>
{
private GeneNode<T> root;
private ArrayList children = new ArrayList();
private int depMax;
string stemp;
public ChromosomeTree()
{
root = null;
}
public virtual void Clear()
{
root = null;
}
public GeneNode<T> Root
{
get
{
return root;
}
set
{
root = value;
}
}
public int MaxDepth
{
get
{
return depMax;
}
set
{
depMax = value;
}
}
public ArrayList Children
{
get
{
return children;
}
}
public GeneNode<T> lastChild()
{
return (GeneNode<T>)this.Children[this.Children.Count - 1];
}
public void addFull(GeneNode<T> node)
{
//check if the chromosome tree has a root if not add the first node as the chromosomes root
if (this.Root == null)
{
this.Root = node;
children.Add(node);
stemp += " " + node.Value;
}
else
{
for (int i = 0; i <= this.Children.Count - 1; i++)
{
GeneNode<T> parent = (GeneNode<T>)this.Children[i];
//check to ensure maxDepth of chromosome tree is not exceeded
if (parent.Depth != this.MaxDepth)
{
//check to see if the current node stil has room for another node to be added to it
if ((parent.Children == null) || (parent.Children[1] == null))
{
children.Add(node);
parent.Add(node);
stemp += " " + node.Value;
break;
}
}
else
{
break;
}
}
}
}
public override string ToString()
{
string chromosome = String.Empty;
foreach(GeneNode<Gene> gene in this.Children)
{
chromosome += " " + gene.Value.GeneValue.ToString();
}
return chromosome;
}
}
Im pretty sure its a simple mistake but ive looked at this for so long I cant see the wood from the trees. Any thoughts would be greatly appreciated.
Many thanks in advance.
Luke
here is the code that utilises the this class.
EDIT : THE OVERWRITE HAPPENS WHEN THE METHOD IS CALLED NOT AFTER THE METHOD HAS EXECUTED ITS LOGIC
class SimpleChromosome
{
Random rand = new Random();
Gene funcGene = new Gene();
Gene termGene = new Gene();
private string sChromosome;
private int currentdepth;
private string grownChromosome()
{
return sChromosome;
}
public ChromosomeTree<Gene> fullChromosome()
{
ChromosomeTree<Gene> chromosone = new ChromosomeTree<Gene>();
//chromosone.MaxDepth = rand.Next(1, 5);
chromosone.MaxDepth = 1;
int maxGenes = (int)Math.Pow(2, chromosone.MaxDepth + 1) - 1;
for (int i = 0; i <= chromosone.MaxDepth; i++)
{
int numNodesForLevel = (int)Math.Pow(2, i);
int numNodesOnLevel = 0;
for (int j = 0; j < numNodesForLevel; j++)
{
if (currentdepth != chromosone.MaxDepth)
{
funcGene.GenerateValue(GeneType.Function);
GeneNode<Gene> geneNode = new GeneNode<Gene>(funcGene);
sChromosome += " " + geneNode.Value;
chromosone.addFull(geneNode);
numNodesOnLevel++;
}
else
{
termGene.GenerateValue(GeneType.Terminal);
GeneNode<Gene> geneNode = new GeneNode<Gene>(termGene);
sChromosome += " " + geneNode.Value;
chromosone.addFull(geneNode);
numNodesOnLevel++;
}
if ((numNodesForLevel == numNodesOnLevel) && (currentdepth != chromosone.MaxDepth))
{
currentdepth++;
}
}
}
currentdepth = 0;
//Console.WriteLine("Before ADD :" + sChromosome);
sChromosome = "";
return chromosone;
}
}
Post the code where you are adding a new object of this type to your ArrayList.
My guess is that you are using two references to the same object.
Remember that objects are reference types, therefore if you assign them to each other you are only assigning their references. e.g. in the following code:
Foo foo1 = new Foo();
foo1.x = 1;
Foo foo2 = new Foo();
foo2.x = 2;
foo2 = foo1; // foo2 now points to the same object as foo1;
// foo1.x does not get copied into foo2.x.
// You have also lost your reference to the original foo2 object here and it will be garbage collected.
foo2.x = 100;
// since foo2 and foo1 are now pointing to the same object. both foo2.x and foo1.x will be 100
For this sort of relationship you really should be coding to interfaces. eg.
public interface IGeneNode{
//genenode definition including perhaps equality interfaces etc
}
If the above is correct then you can overload your Assignment operator to pass the values you wish to pass.
This might be useful to you as well.
C# - Multiple generic types in one list
in this loop parent == Children[i] and Children is a getter for children
Do you really mean to be adding the same node to children and parent, which would make the same node a sibling of parent in addition to a child? I'm not clear on what you're really trying to do but this seems wrong:
if ((parent.Children == null) || (parent.Children[1] == null))
{
children.Add(node);
parent.Add(node);
..
}
edit
From the supporting code you posted the problem could be related to how you create objects:
/* outside the loop */
Gene funcGene = new Gene();
Gene termGene = new Gene();
...
/* inside the loop*/
funcGene.GenerateValue(GeneType.Function);
GeneNode<Gene> geneNode = new GeneNode<Gene>(funcGene);
sChromosome += " " + geneNode.Value;
chromosone.addFull(geneNode);
Seems like you are create a new GeneNode multiple times using a one of two instances of Gene in its constructor. Assuming that your GeneNode is saving that as a property value, each GeneNode is going to reference the same instance of Gene (well, one of two, either funcGene or termGene). I'm guessing this is what you mean when you say new item with the same type as previous items in the ArrayList this new item overwrites the previous items individual properties. Any changes to a Gene property assigned from the constructor in any node of the same type will refer to the same Gene. Even though you are creating new GeneNodes they are constructed from the same Gene.
So assuming that GeneNode.Value references the Gene that it was constructed with, there can only be two different values returned (corresponding to the the current value of one of the two Gene instances) by any node at any given point in time.
Probably, you want to move the code to create a new Gene inside your loop.