Sending an Array to Controls - c#

So, I'm a student beginning to learn C# in school and one of my current projects has come to involve outputting an expandable, class method-bound array to controls on a form, and I've hit a confusing snag. I've set the proper access modifiers to public, I've successfully used this formatting for an expandable array before, and my program shows no build errors, but the data won't output.
I can see my logic error being a part of my array declaration, which in past permutations seemed like it wasn't expanding, though my current strategy, which calls the Expand() method, directly increasing my index noobIdentifier, which is a universal variabel within the class, outside of the actual method.
//Create Form Instance
AttendanceReport report = new AttendanceReport();
//Expand Array
Expand();
//Create Array
int SIZE = noobIdentifier + 1;
Noob[] info = new Noob[SIZE];
//Assign Data to Array
info[noobIdentifier].s_class = Class;
info[noobIdentifier].s_name = Name;
info[noobIdentifier].s_id = ID;
info[noobIdentifier].s_password = Password;
info[noobIdentifier].s_formerDistrict = District;
info[noobIdentifier].s_grade = Grade;
info[noobIdentifier].s_country = Country;
info[noobIdentifier].index = SIZE;
It could also be a part of my actual output block in the same method. I have considered trying to use a For loop instead of a Foreach in my Listbox output, though the latter seemed more concise.
//Ouput Gateway
if (output == true)
{
//Temp Holder
int i;
//Output items to Attendance Report Listbox
foreach (Noob noob in info)
{
//Send Index to string
string indexer = noob.index.ToString();
//Convert to Int
i = int.Parse(indexer);
report.newStudentSelectionBox.Items.Add(i);
}
}
//Output Text Gateway
if (textOutput > 0)
{
//Declare Index
int n = textOutput - 1;
report.classOutput.Text = info[n].s_class;
report.nameOutput.Text = info[n].s_name;
report.idOutput.Text = info[n].s_id.ToString();
report.gradeOutput.Text = info[n].s_grade.ToString();
report.districtOutput.Text = info[n].s_formerDistrict;
report.countryOutput.Text = info[n].s_country;
}
Both output and textOutput are the method inputs, with textOutput being declared as an int so that it can be used as a direct reference to array placements.

Give this a try
In Noob class:
public class Noob
{
//Your Definition...
public override string ToString() => this.Name;
}
Modify loop like:
//Output items to Attendance Report Listbox
foreach (Noob noob in info)
{
report.newStudentSelectionBox.Items.Add(noob);
}

Related

How to iterate through multiple variables?

I'd like to create a short program to download several pictures from a website.
On a form, I would like to enter a root-link to a website with placeholders.
The placeholders can be defined with Start/End value and asc/desc.
For example: the original link is
google.de/1236-01.jpg
and I'd like to generate all links from
google.de/1236-1.jpg
up to
google.de/9955-12.jpg
So my input would be "google.de/[0]-[1].jpg" and placeholders are set to:
[0] = start 1236|end 9955|asc
[1] = start 1|end 12|asc
Via GetValidCharacters() I get a String-List of valid combinations for each entered placeholder (can be selected via ascending/descending + start&end).
The goal I'm struggling with is to build all combinations of this link, because I need to determine while runtime, how much placeholders I have.
My idea was to loop over an queue and enquueue each new build line, until there is none left with placeholders, but I don't know how to do this.
I need to make sure that all combinations are entered and they are entered only once.
private static void CreateDownloadList()
{
Queue<string> tmpQueue = new Queue<string>(); //temp queue
tmpQueue.Enqueue(DL_path); //DL_Path = google.de/[0]-[1].jpg
string line = "";
while ((line = tmpQueue.Dequeue()) != null) //not empty
{
if (line.Contains("[")) //placeholder
{
string tmpLine = line;
//how to determine, which placeholder is next?? need to know this and replace this with every combination, I get from GetValidCharacters(start, end, DESC)
}
else //done
{
_urlList.Add(line);
}
}
}
how about a simple for loop?
for (int i = 1236; i <= 9955; i++)
{
for (int j = 1; j <= 12; j++)
{
tmpQueue.Enqueue(string.Format("google.de/{0}-{1}.jpg", i, j));
}
}
I'm not going give you the full code but here is some pseudo code that would solve the problem.
given :
todostack -- stack object that holds a list of unresolved items
replace_map -- map object that holds marker string and map of all values
marker_list -- list of all markers
final_list -- list object that holds the results
(note you can probably use marker_list and replace_map in one object -- I have them separate to make my code clearer)
init :
push todostack with your starting string
set marker_list and replace_map to correct values (from parameters I assume)
clear final_list
algorithm :
while (there are any items in todostack)
{
curitem = todostack.pop
if (curitem contains a marker in marker_list)
{
loop for each replacement in replace_map
{
new_item = curitem replaced with replacement
todostack.push(new_item)
}
}
else
add curitem to final_list
}
#Hogan this was the hint to the correct way.
solution is this
private void CreateDownloadList()
{
Queue<string> tmpQueue = new Queue<string>();
tmpQueue.Enqueue(downloadPathWithPlaceHolders);
while(tmpQueue.Count > 0)
{
string currentItem = tmpQueue.Dequeue();
bool test = false;
if(currentItem.Contains("["))
{
foreach(Placeholder p in _placeholders)
{
if(currentItem.Contains(p.PlaceHolder))
{
foreach(string s in p.Replacements)
{
tmpQueue.Enqueue(currentItem.Replace(p.PlaceHolder, s));
}
test = true;
}
if(test)
break;
}
}
else
{
_downloadLinkList.Add(currentItem);
}
}
}

How to apply arraylist with variables in an Object, inside a method using a for loop in c #

A hw was given to us to change a previous hw in C# which used 2d arrays and instead of using 2d arrays we use an Array list with variables declared in an object called Students.
I would like to use a method to calculate a student best mark; however, the method is giving me an error and a warning which are the following:
Error:
CS0161 'Form1.Calc_HighestMarkOutput(int)': not all code paths return a value.
Warning:
CS0162 Unreachable code detected.
Inside the arraylist the user inputed (through use of an overload constructor):
Student Name, Maths Mark, English Mark, Maltese Mark, Email Address.
and since in the method I am returning 3 highest marks in 3 subjects attained by all students, I decided to return an array. which will be accessed by a temporary array inside the main program by selectedindex.
Please help me find the problem.
And thanks in advance.
public int[] Calc_HighestMarkOutput(int HighestMarkIndex)
{
int[] HighestMarkOutput = new int[3];
int HighestMarkMaths = 0;
int HighestMarkEnglish = 0;
int HighestMarkMaltese = 0;
int TMPHighestMarkMaths = 0;
int TMPHighestMarkEnglish = 0;
int TMPHighestMarkMaltese = 0;
for (int i = 0; i < myStudents.Count; i++) //a loop through an array list.
{
if (myStudents[HighestMarkIndex].Maths_Result > HighestMarkMaths)
{
TMPHighestMarkMaths = myStudents[HighestMarkIndex].Maths_Result;
HighestMarkMaths = TMPHighestMarkMaths;
}
if (myStudents[HighestMarkIndex].English_Result > HighestMarkEnglish)
{
TMPHighestMarkEnglish = myStudents[HighestMarkIndex].English_Result;
HighestMarkEnglish = TMPHighestMarkEnglish;
}
if (myStudents[HighestMarkIndex].Maltese_Result > HighestMarkMaltese)
{
TMPHighestMarkMaltese = myStudents[HighestMarkIndex].Maltese_Result;
HighestMarkMaltese = TMPHighestMarkMaltese;
}
HighestMarkOutput[0] = HighestMarkMaths;
HighestMarkOutput[1] = HighestMarkEnglish;
HighestMarkOutput[2] = HighestMarkMaltese;
return HighestMarkOutput;
}
You are getting an error, because the return-statement is inside the loop. If the list is empty, the return statement will never be executed. Also, you know the result only after the loop has finished. So, place the return-statement after the loop.
Since the purpose of this method is to find the highest marks, it makes no sense to pass such an index into the routine as a parameter.
Using foreach is easier than for because you don't have to deal with indexes.
Instead of returning an array, return an unnamed student containing the results. You can drop useless temporary variables.
public Student Calc_HighestMarkOutput()
{
var result = new Student(); // You also might have to add a default constructor.
foreach (Student student in myStudents) {
if (student.Maths_Result > result.Maths_Result) {
result.Maths_Result = student.Maths_Result;
}
if (student.English_Result > result.English_Result) {
result.English_Result = student.English_Result;
}
if (student.Maltese_Result > result.Maltese_Result) {
result.Maltese_Result = student.Maltese_Result;
}
}
return result;
}
You could also use Math.Max to simplify finding the maximum value
foreach (Student student in myStudents) {
result.Maths_Result = Math.Max(result.Maths_Result, student.Maths_Result);
result.English_Result = Math.Max(result.English_Result, student.English_Result);
result.Maltese_Result = Math.Max(result.Maltese_Result, student.Maltese_Result);
}
With these refactorings, the method shrinks from 22 lines (not counting empty lines and lines containing only a brace) to 7 lines.

How to access a Object property, in a List of generated Objects

I searched the heck out of it, and i can't solve it.
I have a program setup like this (it's in Unity and Visual Studio 2019 for C#):
Note that the CSV loading goes fine, when i debug the code i can see everything filled with corect data.
#region character class
public class _Character
{
public int Id { get; set; }
public int Variation { get; set; }
public string Name { get; set; }
public string LastName { get; set; }
}
#endregion
//Tools.LoadCsv generates a string[,] from a csv file
//Tools.IntParse parses int's with a lot of format error checking
void Start()
{
#region load characters class
string[,] CharacterCSV = Tools.LoadCsv(#"Assets/GameDB/character.csv");
List<_Character> Character = new List<_Character>();
for (int i = 1; i < CharacterCSV.GetUpperBound(0); i++)
{
_Character temp = new _Character();
temp.Id = Tools.IntParse(CharacterCSV[i, 0]);
temp.Variation = Tools.IntParse(CharacterCSV[i, 1]);
temp.Name = CharacterCSV[i, 2];
temp.LastName = CharacterCSV[i, 3];
Character.Add(temp);
}
CharacterCSV = null;
#endregion
}
I barely understand objects, so i'm sorry if i am doing it wrong.
The questions i have are:
Why does the Object List generation Háve to be in Start ? I can't seem to do that in it's own class.
How can i get an object from the Character Object List, containing Id = 100 and Name = "John"
, and access it from another class or method.
I ussualy frankenstein the heck out of code and make it good enough for me, but now i wanted to make something nice and cant seem to get to the objects.
Thanks in advance!
//the major issue was declaring the object inside the class, when declared outside the class, the List Object was available to the outside world.
List<_Character> Character = new List<_Character>(); move to outside Start{}
I'm not editing the question to correct the code, because the question needs to stay clear.
//
Why does the Object List generation has to be in Start ? I can't seem to do that in it's own class.
How can i get an object from the Character Object List, containing Id = 100 and Name = "John" , and access it from another class or method.
If you want to retrieve a character from outside of the class, then, you have to declare the list outside of the Start function, otherwise, the list will be destroyed since it's a local variable of the function.
// Declare the list outside of the functions
private List<_Character> characters;
void Start()
{
// Avoid using regions, they encourage you to make very long functions with multiple responsabilities, which is not advised
// Instead, create short and simple functions, and call them
LoadCharactersFromCSV();
}
void LoadCharactersFromCSV()
{
string[,] CharacterCSV = Tools.LoadCsv(#"Assets/GameDB/character.csv");
// If you can, indicate the approximate numbers of elements
// It's not mandatory, but it improves a little bit the performances
characters = new List<_Character>( CharacterCSV.GetUpperBound(0) );
// I believe `i` should start at 0 instead of 1
for (int i = 1; i < CharacterCSV.GetUpperBound(0); i++)
{
// I advise you to create a constructor
// instead of accessing the properties one by one
_Character temp = new _Character();
temp.Id = Tools.IntParse(CharacterCSV[i, 0]);
temp.Variation = Tools.IntParse(CharacterCSV[i, 1]);
temp.Name = CharacterCSV[i, 2];
temp.LastName = CharacterCSV[i, 3];
characters.Add(temp);
}
CharacterCSV = null;
}
// Using this function, you will be able to get a character from its id
public _Character GetCharacter( int id )
{
for (int 0 = 1; i < characters.Count; i++)
{
if( characters[i].Id == id )
return characters[i];
}
// Return null if no character with the given ID has been found
return null ;
}
Then, to call GetCharacter from another class:
public class ExampleMonoBehaviour : MonoBehaviour
{
// Replace `TheClassName` by the name of the class above, containing the `Start` function
// Drag & drop in the inspector the gameObject holding the previous class
public TheClassName CharactersManager;
// I use `Start` for the sake of the example
private void Start()
{
// According to your code, `_Character` is defined **inside** the other class
// so you have to use this syntax
// You can get rid of `TheClassName.` if you declare `_Character` outside of it
TheClassName._Character john = CharactersManager.GetCharacter( 100 );
}
}

Manipulating Values in Dictionary

So I have a dictionary whose index is an int, and whose value is a class that contains a list of doubles, the class is built like this:
public class MyClass
{
public List<double> MyList = new List<double>();
}
and the dictionary is built like this:
public static Dictionary<int, MyClass> MyDictionary = new Dictionary<int, MyClass>();
I populate the dictionary by reading a file in line by line, and adding the pieces of the file into a splitstring, of which there is a known number of parts (100), then adding the pieces of the string into the list, and finally into the dictionary. Here's what that looks like:
public void DictionaryFiller()
{
string LineFromFile;
string[] splitstring;
int LineNumber = 0;
StreamReader sr = sr.ReadLine();
while (!sr.EndOfStream)
{
LineFromFile = sr.ReadLine();
splitstring = LineFromFile.Split(',');
MyClass newClass = new MyClass();
for (int i = 1; i < 100; i++)
{
newClass.MyList.Add(Convert.ToDouble(splitstring[i]));
}
MyDictionary.Add(LineNumber, MyClass);
LineNumber++;
}
}
My question is this: is I were to then read another file and begin the DictionaryFiller method again, could I add terms to each item in the list for each value in the dictionary. What I mean by that is, say the file's 1st line started with 10,23,15,... Now, when I read in a second file, lets say its first line begins with 10,13,18,... what I'm looking to have happen is for the dictionary to have the first 3 doubles in its value-list (indexed at 0) to then become 20,36,33,...
Id like to be able to add terms for any number of files read in, and ultimately then take their average by going through the dictionary again (in a separate method) and dividing each term in the value-list by the number of files read in. Is this possible to do? Thanks for any advice you have, I'm a novice programmer and any help you have is appreciated.
Just Replace
newClass.MyList.Add(Convert.ToDouble(splitstring[i]))
with
newClass.MyList.Add(Convert.ToDouble(splitstring[i]) + MyDictionary[LineNumber].GetListOfDouble()[i])
and then replace
MyDictionary.add(Linenumber, Myclass)
with
MyDictionary[linenumber] = MyClass
Just makes sure that the MyDictionary[LineNumber] is not null before adding it :)
Something like this would work
If(MyDictionary[LineNumber] == null)
{
MyDictionnary.add(LIneNUmber, new List<double>());
}
If(MyDictionary[LineNUmber][i] == null)
{
return 0;
}
My solution does not care about list size and it done at reading time not afterward, which should be more efficient than traversing your Dictionary twice.
var current = MyDictionary[key];
for(int i = 0; i < current.MyList.Length; i++)
{
current.MyList[i] = current.MyList[i] + newData[i];
}
Given both lists have same length and type of data.
You can get the custom object by key of the dictionary and then use its list to do any operation. You need to keep track of how many files are read separately.

Save text data to array

I'm very new to working with C#. I am trying to save data (text such as a persons name) which is entered into the console and then 'read' to an array.
The name of the array i want to save data to is: name2convert
The variable collecting the data (name to be converted) is: nameEntered
Any help is very much appreciated. I've been working on this for a few hours and have done several searches, but i have not found any answers which I could understand with my limited understanding of C# at this time. I've only been trying to learn this for a few weeks - i'm very very green. Any help is appreciated.
Note: String names was my test array so that i could see that i knew how to read data back from an array.
I want to save the data to the names2Convert array.
This is my code:
using System;
namespace a061___String_Manipulations___PigLatin
{
///loop - ask for number of names equal to number asked
/// read line, save to array, iterate one up until num equals value asked for
class Program
{
//Arrays
String[] names = { "test01", "test02", "test03", "test04", "test05" }; //Test loop
String[] name2convert = new String[1];
//Variables & Ints?
string title = ">>>-- Welcome to the Highly Enlightening World of Igp-ay Atinl-ay --<<< \n";
string totalIs = "You said you want to convert a total of";
string listCommands = "Is that correct? If so type (Y)es, (R)enter or (Q)uit";// general commands used
string addSuffix ="-ah!"; // Add to end of each name
string nameEntered = "";//name to be converted
int namesTotal = 0;//
//Main Method
public void Play()
{
Console.WriteLine(title); //announce program
askTotal(); //ask number of names
while (true)
{
Console.WriteLine(listCommands);//lists options
String command = Console.ReadLine().ToLower();//reads user command
if (command == "y") // if askTotal true save to array? how?
{
askName();//collects name entered
confirmName();//allows user to confirm spelling, etc.
//y save the array nameEntered name2convert
//name2convert.Add(nameEntered);
name2convert[0] = nameEntered;
//confirm name
for (int i = 0; i < name2convert.Length; i++)
{
Console.WriteLine("Name Aquired: " + name2convert[i]);
}
}
else if (command == "r")
{
askName();//asks name
}
else if (command == "q")
{
Console.WriteLine("Cheers!"); break; //end
}
else
{
Console.WriteLine("Sorry. Invalid Request");//try again
}
PrintList();//test array
}
}
//Helper Methods
public void PrintList()//iterates through, prints names stored in array
{
Console.WriteLine("Print List");
for (int i = 0; i < names.Length; i++)
{
Console.WriteLine((i + 1) + ". " + names[i] + addSuffix);
}
}
//iterates through, prints names stored in array
public void askName()
{
Console.WriteLine("Enter Name: ");//Confirming
String nameEntered = Console.ReadLine().ToLower();// Capture name
Console.WriteLine("Name Captured: " + nameEntered);//confirming name caught
}
//iterates through, prints names stored in array
public void confirmName()
{
Console.WriteLine(listCommands);//Confirming
String command = Console.ReadLine().ToLower();
}
//how many names to convert
public void askTotal()
{
Console.WriteLine("How many names would you like to convert?");//Ask for content
namesTotal = int.Parse(Console.ReadLine());
Console.WriteLine(totalIs + " " + namesTotal);//Confirming
}
//Call Application
static void Main(string[] args)
{
Program StringManipulations = new Program();
StringManipulations.Play(); //Call forth the Pig Latin...
Console.Read();//
}
}
}
Change this:
//y save the array nameEntered name2convert
name2convert.Add(nameEntered);
To this:
name2convert[0] = nameEntered;
EDIT:
In askName() function change:
String nameEntered = Console.ReadLine().ToLower();// Capture name
To:
nameEntered = Console.ReadLine().ToLower();// Capture name
You already have nameEntered of type string declared as property of your class.
And why are you using string and then String? it's the same, as string is alias of String (which is in fact System.String in C#) - but be consistent!
As you already allocated the memory for this array (it's fixed size - in your case it's one).
So to access the first (and only) cell in your array, you should use name2convert[0] - 0 is the first index at any array and usually at any other struct/container in C# (and many other programming languages).
Another approach (as you were trying in your example) is to user List<String> instead.
For more information on arrays and Lists refer to here:
Array tutorial
List tutorial and examples
If you want save EVERY WORD that the user inputs use an List of Strings e.g
List<String> name2convert;
then
name2convert.Add(nameEntered);
to go through the list
foreach (String word in name2convert)
{
Console.WriteLine(word);
}

Categories

Resources