Failing to sort an Array containing objects. C# - c#

I am working on a school project and I have spent 5 hours trying to understand how to go about sorting an Array with an object containing four dimensions. What I set out to do was to sort them by productCode or drinkName. When I read assorted threads people tell OP to use LINQ. I am not supposed to use that and, I get more and more confused as what method to use. I am told by the teacher, to use bubble sort(bad algorithm, I know) and I do that all fine on an Array containing one dimension. I resorted to try Array.Sort but then I get System.InvalidOperationException.
I am going insane and I am stuck even though I read multiple threads on the subject. I might be using ToString in the wrong manner. Any nudge would be appreciated.
class soda
{
string drinkName;
string drinkType;
int drinkPrice;
int productCode;
//Construct for the beverage
public soda(string _drinkName, string _drinkType, int _drinkPrice, int _productCode)
{
drinkName = _drinkName;
drinkType = _drinkType;
drinkPrice = _drinkPrice;
productCode = _productCode;
}
//Property for the drink name e.g. Coca Cola, Ramlösa or Pripps lättöl
public string Drink_name()
{
return drinkName;
//set { drinkName = value; }
}
//Property for the drink type e.g. Soda, fizzy water or beer
public string Drink_type()
{
return drinkType;
//set { drinkType = value; }
}
//Property for the drink price in SEK
public int Drink_price()
{
return drinkPrice;
//set { drinkPrice = value; }
}
//Property for the product code e.g. 1, 2 or ...
public int Product_code()
{
return productCode;
//set { productCode = value; }
}
//Property for the product code e.g. 1, 2 or ...
public int _Product_code
{
get { return productCode; }
set { productCode = value; }
}
public override string ToString()
{
return string.Format(drinkName + " " + drinkType + " " + drinkPrice + " " + productCode);
//return string.Format("The beverage {0} is of the type {1} and costs {2} SEK.", drinkName, drinkType, drinkPrice, productCode);
}
}
class Sodacrate
{
private soda[] bottles; //Crate the array bottles from the class soda.
private int antal_flaskor = 0; //Keeps tracks on the amount of bottles. 25 is the maximum allowed.
//Construct
public Sodacrate()
{
bottles = new soda[25];
}
public void sort_sodas()
{
string drinkName = "";
int drinkPrice = 0;
int productCode = 0;
Array.Sort(bottles, delegate (soda bottle1, soda bottle2) { return bottle1._Product_code.CompareTo(bottle2._Product_code); });
foreach (var beverage in bottles)
{
if (beverage != null)
{
drinkName = beverage.Drink_name(); drinkPrice = beverage.Drink_price(); productCode = beverage.Product_code();
Console.Write(drinkName + " " + drinkPrice + " " + productCode);
}
}
}
}
----------------------edit---------------
Thanks for the help I am getting closer to my solution and have to thursday lunch on me to solve my problems.
Still I have problem with my sort;
//Exception error When I try to have .Product_Name the compiler protests. Invalid token
public void sort_Sodas()
{
int max = bottles.Length;
//Outer loop for complete [bottles]
for (int i = 1; i < max; i++)
{
//Inner loop for row by row
int nrLeft = max - i;
for (int j = 0; j < (max - i); j++)
{
if (bottles[j].Product_code > bottles[j + 1].Product_code)
{
int temp = bottles[j].Product_code;
bottles[j] = bottles[j + 1];
bottles[j + 1].Product_code = temp;
}
}
}
}
Also my Linear search only returns one vallue when I want all those that are true to the product group. I tried a few different things in the Run() for faster experimentation. I will append the current code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Sodacrate
{
//Soda - contains the properties for the bottles that go in to the crate
class Soda : IComparable<Soda>
{
string drinkName;
string drinkType;
int drinkPrice;
int productCode;
//Construct for the beverage
public Soda(string _drinkName, string _drinkType, int _drinkPrice, int _productCode)
{
drinkName = _drinkName;
drinkType = _drinkType;
drinkPrice = _drinkPrice;
productCode = _productCode;
}
//Property for the drink name e.g. Coca Cola, Ramlösa or Pripps lättöl
public string Drink_name
{
get { return drinkName; }
set { drinkName = value; }
}
//Property for the drink type e.g. Soda, fizzy water or beer
public string Drink_type
{
get { return drinkType; }
set { drinkType = value; }
}
//Property for the drink price in SEK
public int Drink_price
{
get { return drinkPrice; }
set { drinkPrice = value; }
}
//Property for the product code e.g. 1, 2 or ...
public int Product_code
{
get { return productCode; }
set { productCode = value; }
}
//Override for ToString to get text instead of info about the object
public override string ToString()
{
return string.Format("{0,0} Type {1,-16} Price {2,-10} Code {3, -5} ", drinkName, drinkType, drinkPrice, productCode);
}
//Compare to solve my issues with sorting
public int CompareTo(Soda other)
{
if (ReferenceEquals(other, null))
return 1;
return drinkName.CompareTo(other.drinkName);
}
}
static class Screen
{
// Screen - Generic methods for handling in- and output ======================================= >
// Methods for screen handling in this object are:
//
// cls() Clear screen
// cup(row, col) Positions the curser to a position on the console
// inKey() Reads one pressed key (Returned value is : ConsoleKeyInfo)
// inStr() Handles String
// inInt() Handles Int
// inFloat() Handles Float(Singel)
// meny() Menu system , first invariable is Rubrik and 2 to 6 meny choises
// addSodaMenu() The options for adding bottles
// Clear Screen ------------------------------------------
static public void cls()
{
Console.Clear();
}
// Set Curser Position ----------------------------------
static public void cup(int column, int rad)
{
Console.SetCursorPosition(column, rad);
}
// Key Input --------------------------------------------
static public ConsoleKeyInfo inKey()
{
ConsoleKeyInfo in_key; in_key = Console.ReadKey(); return in_key;
}
// String Input -----------------------------------------
static public string inStr()
{
string in_string; in_string = Console.ReadLine(); return in_string;
}
// Int Input -------------------------------------------
static public int inInt()
{
int int_in; try { int_in = Int32.Parse(Console.ReadLine()); }
catch (FormatException) { Console.WriteLine("Input Error \b"); int_in = 0; }
catch (OverflowException) { Console.WriteLine("Input Owerflow\b"); int_in = 0; }
return int_in;
}
// Float Input -------------------------------------------
static public float inFloat()
{
float float_in; try { float_in = Convert.ToSingle(Console.ReadLine()); }
catch (FormatException) { Console.WriteLine("Input Error \b"); float_in = 0; }
catch (OverflowException) { Console.WriteLine("Input Owerflow\b"); float_in = 0; }
return float_in;
}
// Menu ------------------------------------------------
static public int meny(string rubrik, string m_val1, string m_val2)
{ // Meny med 2 val ---------------------
int menSvar; menyRubrik(rubrik); menyRad(m_val1); menyRad(m_val2); menSvar = menyInm();
return menSvar;
}
static public int meny(string rubrik, string m_val1, string m_val2, string m_val3)
{ // Meny med 3 val ---------------------
int menSvar; menyRubrik(rubrik); menyRad(m_val1); menyRad(m_val2); menyRad(m_val3); menSvar = menyInm();
return menSvar;
}
static public int meny(string rubrik, string m_val1, string m_val2, string m_val3, string m_val4)
{ // Meny med 4 val ---------------------
int menSvar; menyRubrik(rubrik); menyRad(m_val1); menyRad(m_val2); menyRad(m_val3); menyRad(m_val4); menSvar = menyInm();
return menSvar;
}
static public int meny(string rubrik, string m_val1, string m_val2, string m_val3, string m_val4, string m_val5)
{ // Meny med 5 val ---------------------
int menSvar; menyRubrik(rubrik); menyRad(m_val1); menyRad(m_val2); menyRad(m_val3); menyRad(m_val4); menyRad(m_val5); menSvar = menyInm();
return menSvar;
}
static public int meny(string rubrik, string m_val1, string m_val2, string m_val3, string m_val4, string m_val5, string m_val6)
{ // Meny med 6 val ---------------------
int menSvar; menyRubrik(rubrik); menyRad(m_val1); menyRad(m_val2); menyRad(m_val3); menyRad(m_val4); menyRad(m_val5); ; menyRad(m_val6); menSvar = menyInm();
return menSvar;
}
static void menyRubrik(string rubrik)
{ // Meny rubrik --------
cls(); Console.WriteLine("\n\t {0}\n----------------------------------------------------\n", rubrik);
}
static void menyRad(string menyVal)
{ // Meny rad --------
Console.WriteLine("\t {0}", menyVal);
}
static int menyInm()
{ // Meny inmating ------
int mVal; Console.Write("\n\t Menyval : "); mVal = inInt(); return mVal;
}
// Menu for adding bottles --------------------------------
static public void addSodaMenu()
{
cls();
Console.WriteLine("\tChoose a beverage please.");
Console.WriteLine("\t1. Coca Cola");
Console.WriteLine("\t2. Champis");
Console.WriteLine("\t3. Grappo");
Console.WriteLine("\t4. Pripps Blå lättöl");
Console.WriteLine("\t5. Spendrups lättöl");
Console.WriteLine("\t6. Ramlösa citron");
Console.WriteLine("\t7. Vichy Nouveu");
Console.WriteLine("\t9. Exit to main menu");
Console.WriteLine("\t--------------------\n");
}
// Screen - Slut <========================================
} // screen <----
class Sodacrate
{
// Sodacrate - Methods for handling arrays and lists of Soda-objects ======================================= >
// Methods for Soda handling in this object are:
//
// cls() Clear screen
//
//
private Soda[] bottles; //Create they array where we store the up to 25 bottles
private int antal_flaskor = 0; //Keep track of the number of bottles in the crate
//Inte Klart saknar flera träffar samt exception
public int find_Soda(string drinkname)
{
//Betyg C
//Beskrivs i läroboken på sidan 147 och framåt (kodexempel på sidan 149)
//Man ska kunna söka efter ett namn
//Man kan använda string-metoderna ToLower() eller ToUpper()
for (int i = 0; i < bottles.Length; i++)
{
if (bottles[i].Drink_name == drinkname)
return i;
}
return -1;
}
//Exception error
public void sort_Sodas()
{
int max = bottles.Length;
//Outer loop for complete [bottles]
for (int i = 1; i < max; i++)
{
//Inner loop for row by row
int nrLeft = max - i;
for (int j = 0; j < (max - i); j++)
{
if (bottles[j].Product_code > bottles[j + 1].Product_code)
{
int temp = bottles[j].Product_code;
bottles[j] = bottles[j + 1];
bottles[j + 1].Product_code = temp;
}
}
}
}
/*
//Exception error
public void sort_Sodas_name()
{
int max = bottles.Length;
//Outer loop for complete [bottles]
for (int i = 1; i < max; i++)
{
//Inner loop for row by row
int nrLeft = max - i;
for (int j = 0; j < (max - i); j++)
{
if (bottles[j].Drink_name > bottles[j + 1].Drink_name)
{
int temp = bottles[j].Drink_name;
bottles[j] = bottles[j + 1];
bottles[j + 1].Drink_name = temp;
}
}
}
}
*/
//Search for Product code
public int LinearSearch(int key)
{
for (int i = 0; i < bottles.Length; i++)
{
if (bottles[i].Product_code == key)
return i;
}
return -1;
}
//Contains the menu to choose from the crates methods
public void Run()
{
bottles[0] = new Soda("Coca Cola", "Soda", 5, 1);
bottles[1] = new Soda("Champis", "Soda", 6, 1);
bottles[2] = new Soda("Grappo", "Soda", 4, 1);
bottles[3] = new Soda("Pripps Blå", "beer", 6, 2);
bottles[4] = new Soda("Spendrups", "beer", 6, 2);
bottles[5] = new Soda("Ramlösa", "water", 4, 3);
bottles[6] = new Soda("Loka", "water", 4, 3);
bottles[7] = new Soda("Coca Cola", "Soda", 5, 1);
foreach (var beverage in bottles)
{
if (beverage != null)
Console.WriteLine(beverage);
}
Console.WriteLine("\n\tYou have {0} bottles in your crate:\n\n", bottleCount());
Console.WriteLine("\nTotal value of the crate\n");
int total = 0;
for (int i = 0; i < bottleCount(); i++)
{
total = total + (bottles[i].Drink_price);
}
/* int price = 0; //Causes exception error
foreach(var bottle in bottles)
{
price = price + bottle.Drink_price;
}
*/
Console.WriteLine("\tThe total value of the crate is {0} SEK.", total);
// Console.WriteLine("\tThe total value of the crate is {0} SEK.", price);
Screen.inKey();
Screen.cls();
int test = 0;
test = bottles[3].Product_code;
Console.WriteLine("Product code {0} is in slot {1}", test, 3);
Screen.inKey();
Console.WriteLine("Type 1, 2 or 3");
int prodcode = Screen.inInt();
Console.WriteLine(LinearSearch(prodcode));
Console.WriteLine("Product code {0} is in slot {1}", prodcode, (LinearSearch(prodcode)));
Console.WriteLine(bottles[(LinearSearch(prodcode))]);
Screen.inKey();
// sort_Sodas(); //Causes Exception error I want it to sort on either product code or product name
foreach (var beverage in bottles)
{
if (beverage != null)
Console.WriteLine(beverage);
}
}
//Print the content of the crate to the console
public void print_crate()
{
foreach (var beverage in bottles)
{
if (beverage != null)
Console.WriteLine(beverage);
//else
//Console.WriteLine("Empty slot");
}
Console.WriteLine("\n\tYou have {0} bottles in your crate:", bottleCount());
}
//Construct, sets the Sodacrate to hold 25 bottles
public Sodacrate()
{
bottles = new Soda[25];
}
// Count the ammounts of bottles in crate
public int bottleCount()
{
int cnt = antal_flaskor;
// Loop though array to get not empty element
foreach (var beverages in bottles)
{
if (beverages != null)
{
cnt++;
}
}
return cnt;
}
//Calculates the total value of the bottles in the crate
public int calc_total()
{
int temp = 0;
for (int i = 0; i < bottleCount(); i++)
{
temp = temp + (bottles[i].Drink_price);
}
return temp;
}
//Adds bottles in the crate.
public void add_Soda()
{
/*Metod för att lägga till en läskflaska
Om ni har information om både pris, läsktyp och namn
kan det vara läge att presentera en meny här där man kan
välja på förutbestämda läskflaskor. Då kan man också rätt enkelt
göra ett val för att fylla läskbacken med slumpade flaskor
*/
//I start of with adding 7 bottles to avoid having to add so many bottles testing functions. Remove block before release
bottles[0] = new Soda("Coca Cola", "Soda", 5, 1);
bottles[1] = new Soda("Champis", "Soda", 6, 1);
bottles[2] = new Soda("Grappo", "Soda", 4, 1);
bottles[3] = new Soda("Pripps Blå", "lättöl", 6, 2);
bottles[4] = new Soda("Spendrups", "lättöl", 6, 2);
bottles[5] = new Soda("Ramlösa citron", "mineralvatten", 4, 3);
bottles[6] = new Soda("Vichy Nouveu", "mineralvatten", 4, 3);
//<======================================================================================================= End block
int beverageIn = 0; //Creates the menu choice-variable
while (beverageIn != 9) //Exit this menu by typing 9 - This value should be different if we add more bottle types to add.
{
Screen.addSodaMenu(); //Calls the menu in the Screen-class
Console.WriteLine("You have {0} bottles in the crate.\n\nChoose :", bottleCount());
Screen.cup(8, 13);
int i = bottleCount(); //Keeps track of how many bottles we have in the crate. If the crate is full we get expelled out of this method
if (i == 25)
{ beverageIn = 9; }
else beverageIn = Screen.inInt(); //end
switch (beverageIn) //Loop for adding bottles to the crate exit by pressing 9
{
case 1:
i = bottleCount();
bottles[i] = new Soda("Coca Cola", "Soda", 5, 1);
i++;
break;
case 2:
i = bottleCount();
bottles[i] = new Soda("Champis", "Soda", 6, 1);
i++;
break;
case 3:
i = bottleCount();
bottles[i] = new Soda("Grappo", "Soda", 4, 1);
i++;
break;
case 4:
i = bottleCount();
bottles[i] = new Soda("Pripps Blå lättöl", "lättöl", 6, 2);
i++;
break;
case 5:
i = bottleCount();
bottles[i] = new Soda("Spendrups lättöl", "lättöl", 6, 2);
i++;
break;
case 6:
i = bottleCount();
bottles[i] = new Soda("Ramlösa citron", "mineralvatten", 4, 3);
i++;
break;
case 7:
i = bottleCount();
bottles[i] = new Soda("Vichy Nouveu", "mineralvatten", 4, 3);
i++;
break;
case 9:
i = bottleCount();
if (i == 25)
{
Console.WriteLine("\tThe crate is full\n\tGoing back to main menu. Press a key: ");
}
Console.WriteLine("Going back to main menu. Press a key: ");
break;
default: //Default will never kick in as I have error handling in Screen.inInt()
Console.WriteLine("Error, pick a number between 1 and 7 or 9 to end.");
break;
}
}
}
// Sodacrate - End <========================================
class Program
{
public static void Main(string[] args)
{
//Skapar ett objekt av klassen Sodacrate som heter Sodacrate
var Sodacrate = new Sodacrate();
Sodacrate.Run();
Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
}
}
}
}

In order to sort objects of a given kind you need to know how to compare two objects to begin with. You can sort an array of numbers because you know how to comparte 1 with 2 and 2 with -10 and so on.
Nowhere in your code are you defining how two sodas (that should be Soda by the way) compare to each other. One way to do this in c# (and .NET in general) is making your class implement a very specific interface named IComparable<T>:
public interface IComparable<T>
{
int CompareTo(T other);
}
CompareTo is what sorting algorithms like Array.Sort or Linq's OrderBy use (if not told otherwise). You need to do the same. T is a generic type, in your case you are interested in comparing sodas with sodas, so T would be Soda.
The CompareTo convention in .NET is as follows:
If this equals other return 0.
If this is less than other return -1.
If this is greater than other return 1.
null is considered to be smaller than any non null value.
Your implementation must follow this convention in order for built in sorting algorithms to work.
So first off, you need to define how you want your soda's to compare. By name? By price? All seem logical choices. If your problem specifies how sodas should compare then implement the comparison logic accordingly, otherwise choose a reasonable option.
I'll go with ordering by name, so I'd do the following:
public class Soda: IComparable<Soda>
{
....
public int CompareTo(Soda other)
{
if (ReferenceEquals(other, null))
return 1;
return drinkName.CompareTo(other.drinkName);
}
}
Because string implements IComparable<string>, implementing my own comparison logic is pretty straightforward.
Ok, now sodas know how to compare to each other and things like Array.Sort will work perfectly fine. Your own bubble sort algorithm should work well too, now that you know how to compare your softdrinks.
Another option would be to implement a IComparer<T> which is basically an object that knows how to compare two Sodas. Look into it, although in your case I think implementing IComparable<T> is a cleaner solution.
On another page, there are a few things about your code that can and should be improved:
soda should be named Soda. Classes should start with a capital letter (except maybe private nested ones).
Use properties instead of methods for Drink_name, Drink_price, Drink_type etc. and better yet, use autoimplemented properties to reduce boilerplate code.
Remove Drink form property names, the class is named Soda, so Drink is pretty much redundant not adding any useful information; its just making property names longer for no reason.
If you insist on keeping Drink use camel casing and remove _: DrinkName, DrinkType, etc.

Related

Problem with My Class Variables Array is not working as intended - C#

To give some context. So for this project I have an array of my class variables, the cd1. That is the variable for the AudioCD and it is an array because if the user wants to enter more CD in to the array.
The problem I am getting is that when I enter more then one cd into the class array, at around the part where I add the string or artist is where I get the issue. When I go to print the class variables specific index which should be seperate, mostly everything except the artist array for the shows the last entered lines for some weird reason. I am trying to figure out why it is doing this.
PS. Sorry is my explanation is not the best.
As you see in the image. The out put should be when I input 1 for choice and 1 for the CD, the array should use the array for index 0, but it is using the array from the last inputted CD. The output should be:
man1
man2
man3
but it is:
man4
man5
man6
class AudioCD
{
// Private Variables for CDclass
public string cdTitle { get; private set; }
private string[] artists = new string[4];
public int releaseYear { get; private set; }
public string genre { get; private set; }
public float condition { get; private set; }
// Constructor for the CDclass - initializes all variables used in the CDclass
public AudioCD()
{
cdTitle = "";
artists = new string[] {"","","",""};
releaseYear = 1980;
genre = "";
condition = 0.0f;
}
// Overload Constructor for the CDclass - initializes all the variables to user input variables
public AudioCD(string cdt, string[] art, int reY, string gen, float con)
{
cdTitle = cdt;
if (artists.Length < art.Length)
{
Console.WriteLine("Your Array size is bigger then 4 for the Artist so the first 4 names will be used!");
}
artists = art;
if (reY < 1980)
{
releaseYear = 1980;
}
else
{
releaseYear = reY;
}
genre = gen;
if (con < 0.0f || con > 5.0f)
{
condition = 0.0f;
}
else
{
condition = con;
}
}
public void printAudioCD()
{
Console.Write(cdTitle + ", " + releaseYear + "\n" );
for (int i = 0; i < artists.Length; i++)
{
if (artists[i] != "" )
{
Console.WriteLine("Artist (#" + (i + 1) + "): " + artists[i]);
}
}
Console.WriteLine("Genre: " + genre);
Console.WriteLine("Condition: " + condition);
}
}
and Program class:
class Program
{
static void Main(string[] args)
{
// variables
string uI, cdtitle, genre;
int size = 0, releaseYear, choice, arrInd;
string[] artistArray = new string[4] {"", "", "", "" };
float condition;
//
AudioCD remote = new AudioCD();
Console.Write("How many CDs do you have lying around your car? ");
uI = Console.ReadLine();
size = Convert.ToInt32(uI);
AudioCD[] cd1 = new AudioCD[size];
for (int i = 0; i < size; i++)
{
Console.WriteLine("CD #" + (i + 1));
Console.Write("*Enter Title: ");
uI = Console.ReadLine();
cdtitle = uI;
Console.WriteLine("*Enter Artists (type -1 when finished):");
int j = 0;
do
{
uI = Console.ReadLine();
if (uI != "-1")
artistArray[j] = uI;
j++;
// Resize the array by One Element
if (j >= 4 && uI != "-1")
{
Array.Resize(ref artistArray, artistArray.Length + 1);
artistArray[j] = "";
}
} while (uI != "-1" );
Console.Write("*Enter Genre: ");
uI = Console.ReadLine();
genre = uI;
Console.Write("*Enter Release Year: ");
uI = Console.ReadLine();
releaseYear = Convert.ToInt32(uI);
Console.Write("*Enter Condition: ");
uI = Console.ReadLine();
condition = float.Parse(uI);
Console.Write("\n");
// switch to select which class of cd to put information in
cd1[i] = new AudioCD(cdtitle, artistArray, releaseYear, genre, condition);
}
bool isPlaying = true;
while(isPlaying)
{
Console.Write("\n");
Console.WriteLine("[Main Menu]");
Console.WriteLine("1) Album Info");
Console.WriteLine("2) Find a CD");
Console.WriteLine("3) Find an artist");
Console.WriteLine("4) Log off");
Console.Write("Choice: ");
uI = Console.ReadLine();
choice = Convert.ToInt32(uI);
switch(choice)
{
case 1:
{
Console.Write("\nWhich CD do you want? ");
uI = Console.ReadLine();
arrInd = Convert.ToInt32(uI);
if (arrInd >= 1 || arrInd <= size)
{
Console.Write(arrInd + ". ");
cd1[(arrInd - 1)].printAudioCD();
}
break;
}
case 2:
{
break;
}
case 3:
{
break;
}
case 4:
{
isPlaying = false;
break;
}
default:
{
break;
}
}
}
}
}
OUTPUT
As you see in the image. The out put should be when I input 1 for choice and 1 for the CD, the array should use the array for index 0, but it is using the array from the last inputted CD. The output should be man1,man2, and man3, but it is man4, man5, and man6.
You are using the same array in your Main() for each iteration and this is the reason why you got the artists from the last inputted CD. I mean this code snippet:
string[] artistArray = new string[4] {"", "", "", "" };
Here we can use List<T> to avoid writing code of resizing of an array and we can use Clear() method to avoid storing artists from the previous CD.
The whole code would look like this. I've refactored your code a little bit by using List:
The class AudioCD:
public class AudioCD
{
// Private Variables for CDclass
public string cdTitle { get; private set; }
private List<string> artists = new List<string>();
public int releaseYear { get; private set; }
public string genre { get; private set; }
public float condition { get; private set; }
// Constructor for the CDclass - initializes all variables used in the CDclass
public AudioCD()
{
cdTitle = "";
releaseYear = 1980;
genre = "";
condition = 0.0f;
}
// Overload Constructor for the CDclass - initializes all the variables to user input variables
public AudioCD(string cdt, List<string> art, int reY, string gen, float con)
{
cdTitle = cdt;
artists.AddRange(art);
if (reY < 1980)
{
releaseYear = 1980;
}
else
{
releaseYear = reY;
}
genre = gen;
if (con < 0.0f || con > 5.0f)
{
condition = 0.0f;
}
else
{
condition = con;
}
}
public void printAudioCD()
{
Console.Write(cdTitle + ", " + releaseYear + "\n");
for (int i = 0; i < artists.Count; i++)
{
if (artists[i] != "")
{
Console.WriteLine("Artist (#" + (i + 1) + "): " + artists[i]);
}
}
Console.WriteLine("Genre: " + genre);
Console.WriteLine("Condition: " + condition);
}
}
and Main method would look like this:
// variables
string uI, cdtitle, genre;
int size = 0, releaseYear, choice, arrInd;
List<string> artistArray = new List<string>();
float condition;
Console.Write("How many CDs do you have lying around your car? ");
uI = Console.ReadLine();
size = Convert.ToInt32(uI);
AudioCD[] cd1 = new AudioCD[size];
for (int i = 0; i < size; i++)
{
Console.WriteLine("CD #" + (i + 1));
Console.Write("*Enter Title: ");
uI = Console.ReadLine();
cdtitle = uI;
Console.WriteLine("*Enter Artists (type -1 when finished):");
int j = 0;
do
{
uI = Console.ReadLine();
if (uI != "-1")
artistArray[j] = uI;
j++;
} while (uI != "-1");
Console.Write("*Enter Genre: ");
uI = Console.ReadLine();
genre = uI;
Console.Write("*Enter Release Year: ");
uI = Console.ReadLine();
releaseYear = Convert.ToInt32(uI);
Console.Write("*Enter Condition: ");
uI = Console.ReadLine();
condition = float.Parse(uI);
Console.Write("\n");
// switch to select which class of cd to put information in
cd1[i] = new AudioCD(cdtitle, artistArray, releaseYear, genre, condition);
artistArray.Clear();
}
bool isPlaying = true;
while (isPlaying)
{
Console.Write("\n");
Console.WriteLine("[Main Menu]");
Console.WriteLine("1) Album Info");
Console.WriteLine("2) Find a CD");
Console.WriteLine("3) Find an artist");
Console.WriteLine("4) Log off");
Console.Write("Choice: ");
uI = Console.ReadLine();
choice = Convert.ToInt32(uI);
switch (choice)
{
case 1:
{
Console.Write("\nWhich CD do you want? ");
uI = Console.ReadLine();
arrInd = Convert.ToInt32(uI);
if (arrInd >= 1 || arrInd <= size)
{
Console.Write(arrInd + ". ");
cd1[(arrInd - 1)].printAudioCD();
}
break;
}
case 2:
{
break;
}
case 3:
{
break;
}
case 4:
{
isPlaying = false;
break;
}
default:
{
break;
}
}
}

C# How can I write console output to a file?

I need to get my console output to a text file also. How can this be possible with the following code? I hope that a routined person can help me out :-)
namespace MyProject
{
// Creating a class for salesmen
class Person
{
// Variables for the salesmen
public string name;
public long personNumber;
public string district;
public int soldArticles;
// Constructor for the class
public Person(string name, long personNumber, string district, int soldArticles)
{
this.name = name;
this.personNumber = personNumber;
this.district = district;
this.soldArticles = soldArticles;
}
// Method to read input from user about the salesmen
public static Person ReadSeller()
{
Console.Write("\nEnter name of the salesman: ");
string name = Console.ReadLine();
Console.Write("\nPlease enter person number: ");
long personNumber = long.Parse(Console.ReadLine());
Console.Write("\nPlease enter what district you operate in: ");
string district = Console.ReadLine();
Console.Write("\nPlease enter amount of sold articles: ");
int soldArticles = int.Parse(Console.ReadLine());
return new Person(name, personNumber, district, soldArticles);
}
}
class Program
{
static void Main(string[] args)
{
// prompt user to enter how many salesmen there are in the salesforce
Console.Write("\nHow many salesmen are you in the salesforce? ");
int numOfSalesmen = int.Parse(Console.ReadLine());
// List that holds the salesmen
List<Person> sellers = new List<Person>();
// for loop that will iterate through the given amount of salesmen
for (int i = 1; i <= numOfSalesmen; i++)
{
Console.WriteLine("\nPlease fill in data for salesman {0}", i);
sellers.Add(Person.ReadSeller());
Console.WriteLine("--------------------------------------------------");
}
// sort the list with bubblesort
SortByBubblesort(sellers);
// print the salesmen
PrintSalesmen(sellers);
}
// This method sorts the List Person with the bubblesort method from least to most sold articles.
static List<Person> SortByBubblesort(List<Person> sellers)
{
int timesNumbersChanged;
do
{
timesNumbersChanged = 0;
for (int i = 0; i < sellers.Count - 1; i++)
{
if (sellers[i].soldArticles > sellers[i + 1].soldArticles)
{
Person salesman = sellers[i];
sellers.RemoveAt(i);
sellers.Insert(i + 1, salesman);
timesNumbersChanged += 1;
}
}
} while (timesNumbersChanged != 0);
return sellers;
}
// This method prints the salesmen in the order of what level they belong to.
static List<Person> PrintSalesmen(List<Person> sellers)
{
// Constants & variables
const int LEVEL_ONE = 50;
const int LEVEL_TWO = 99;
const int LEVEL_THREE = 199;
const int LEVEL_FOUR = 200;
int count = 0;
// headline for the output
Console.WriteLine("{0,-20} {1,-20} {2,-10} {3,-10}", "Name", "Person number", "District", "Articles sold");
// Counts how many salesmen that belongs to level 1
foreach (Person salesman in sellers)
{
if (salesman.soldArticles < LEVEL_ONE)
{
count++;
Console.Write("\n{0,-20} {1,-20} {2,-10} {3,-10}", salesman.name, salesman.personNumber, salesman.district, salesman.soldArticles);
}
}
// bottomline for level 1.
Console.WriteLine("\n" + count + " Salesmen reached level 1: Under 50 articles");
// Counts how many salesmen that belong to level 2
count = 0;
foreach (Person salesman in sellers)
{
if (salesman.soldArticles >= LEVEL_ONE && salesman.soldArticles <= LEVEL_TWO)
{
count++;
Console.Write("\n{0,-20} {1,-20} {2,-10} {3,-10}", salesman.name, salesman.personNumber, salesman.district, salesman.soldArticles);
}
}
// bottomline for level 2.
Console.WriteLine("\n" + count + " Salesmen reached level 2: 50-99 articles");
// Counts how many salesmen that belongs to level 3
count = 0;
foreach (Person salesman in sellers)
{
if (salesman.soldArticles > LEVEL_TWO && salesman.soldArticles <= LEVEL_THREE)
{
count++;
Console.Write("\n{0,-20} {1,-20} {2,-10} {3,-10}", salesman.name, salesman.personNumber, salesman.district, salesman.soldArticles);
}
}
// bottomline for level 3.
Console.WriteLine("\n" + count + " Salesmen reached level 3: 100-199 articles");
// Counts how many salesmen that belongs to level 4
count = 0;
foreach (Person salesman in sellers)
{
if (salesman.soldArticles >= LEVEL_FOUR)
{
count++;
Console.Write("\n{0,-20} {1,-20} {2,-10} {3,-10}", salesman.name, salesman.personNumber, salesman.district, salesman.soldArticles);
}
}
// bottomline for level 4.
Console.WriteLine("\n" + count + " Salesmen reached level 4: Over 199 articles");
return sellers;
}
}
}
Use Console.SetOut(...)
https://learn.microsoft.com/en-us/dotnet/api/system.console.setout?view=net-6.0.
In general I would suggest to replace Console with an logging framework. e.g. Log4Net:
https://stackify.com/log4net-guide-dotnet-logging/

matching the answer in C#

so i have this question :
"1. The word 'virile' means what?\na. Like a rabbit\nb. Like a man\nc. Like a wolf\nd. Like a horse\n"
As you can see its one string separated with \n for each choice . (a , b , c , d )
so i wrote a code to check where is the answer whether its on a , b , c or d
ans = "Like a man";
if (data.Content.StartsWith("a") && data.Content.Contains(ans))
{
Reply("a");
}
else if (data.Content.StartsWith("b") && data.Content.Contains(ans))
{
Reply("b");
}
else if (data.Content.StartsWith("c") && data.Content.Contains(ans))
{
Reply("c");
}
else if (data.Content.StartsWith("d") && data.Content.Contains(ans))
{
Reply("d");
}
It give me 'a' as it's the answer. I know why , its because im using Startwith , which it's wrong because the (data.content) starts with the question its self since its one string .
my question is :
how i can make the program look for any match in the question for my answer then write whatever it was a , b , c or d
Maybe this LINQ solution will be helpful:
string input = "1. The word 'virile' means what?\na. Like a rabbit\nb. Like a man\nc. Like a wolf\nd. Like a horse\n";
string[] inputSplit = input.Split(new string[] { "\n" }, StringSplitOptions.RemoveEmptyEntries);
string ans = "Like a man";
string result = new string(inputSplit.Where(x => x.Contains(ans))
.Select(x => x[0]).ToArray());
Reply(result);
result= b
Check if this helps you.
private string question = "1. The word 'virile' means what?\na. Like a rabbit\nb. Like a man\nc. Like a wolf\nd. Like a horse\n"; // your question
string ans = "Like a man"; // your answer
string[] allAnswers = question.Split('\n');
for (int i = 1; i < 5; i++) { // index 0 contains the question
if (answers[i].Contains(ans)) {
Reply(answers[i][0].ToString()); // toString since [0] returns the first char, in your case will be the answer.
}
}
public char GetQuestionRef(string question, string answer)
{
string[] answers = question.Split('\n');
char question;
for(int i = 1; i < answers.Length; i++)
{
if(answers[i].Contains(answer))
{
question = answers[i].Substring(0, 1);
}
}
return question;
}
Another way to do this is to create a class that holds the properties of a "quiz item", such as the Question, a list of Possible Answers, and the Correct Answer Index. We can also give this class the ability to ask the question, display the answers, get a response from the user and then return true or false if the response is correct.
For example:
public class QuizItem
{
public string Question { get; set; }
public List<string> PossibleAnswers { get; set; }
public bool DisplayCorrectAnswerImmediately { get; set; }
public int CorrectAnswerIndex { get; set; }
public bool AskQuestionAndGetResponse()
{
Console.WriteLine(Question + Environment.NewLine);
for (int i = 0; i < PossibleAnswers.Count; i++)
{
Console.WriteLine($" {i + 1}. {PossibleAnswers[i]}");
}
int response = GetIntFromUser($"\nEnter answer (1 - {PossibleAnswers.Count}): ",
1, PossibleAnswers.Count);
if (DisplayCorrectAnswerImmediately)
{
if (response == CorrectAnswerIndex + 1)
{
Console.WriteLine("\nThat's correct, good job!");
}
else
{
Console.WriteLine("\nSorry, the correct answer is: {0}",
$"{CorrectAnswerIndex + 1}. {PossibleAnswers[CorrectAnswerIndex]}");
}
}
return response == CorrectAnswerIndex + 1;
}
// This helper method gets an integer from the user within the specified bounds
private int GetIntFromUser(string prompt, int min, int max)
{
int response;
do
{
Console.Write(prompt);
} while (!int.TryParse(Console.ReadLine(), out response) ||
response < min || response > max);
return response;
}
}
Now that we have a class that represents a QuizItem, we can create another class to represent the Quiz itself. This class would have a list of quiz items, would be able to present each item to the user, save the responses, and display the results of the quiz.
For example:
public class Quiz
{
public Quiz(User user)
{
if (user == null) throw new ArgumentNullException(nameof(user));
User = user;
QuizItems = new List<QuizItem>();
}
public List<QuizItem> QuizItems { get; set; }
public User User { get; set; }
public DateTime StartTime { get; private set; }
public DateTime EndTime { get; private set; }
public void BeginTest()
{
Console.Clear();
if (QuizItems == null)
{
Console.WriteLine("There are no quiz items available at this time.");
return;
}
Console.WriteLine($"Welcome, {User.Name}! Your quiz will begin when you press a key.");
Console.WriteLine($"There are {QuizItems.Count} multiple choice questions. Good luck!\n");
Console.Write("Press any key to begin (or 'Q' to quit)...");
if (Console.ReadKey().Key == ConsoleKey.Q) return;
Console.SetCursorPosition(0, Console.CursorTop);
Console.Write(new string(' ', Console.WindowWidth));
Console.SetCursorPosition(0, Console.CursorTop - 1);
var itemNumber = 1;
StartTime = DateTime.Now;
foreach (var item in QuizItems)
{
Console.WriteLine($"Question #{itemNumber}");
Console.WriteLine("-------------");
itemNumber++;
var result = item.AskQuestionAndGetResponse();
User.QuestionsAnswered++;
if (result) User.CorrectAnswers++;
}
EndTime = DateTime.Now;
var quizTime = EndTime - StartTime;
Console.WriteLine("\nThat was the last question. You completed the quiz in {0}",
$"{quizTime.Minutes} minues, {quizTime.Seconds} seconds.");
Console.WriteLine("\nYou answered {0} out of {1} questions correctly, for a grade of '{2}'",
User.CorrectAnswers, User.QuestionsAnswered, User.LetterGrade);
}
}
This class makes use of a User class, which is used to store the user name and their results:
public class User
{
public User(string name)
{
Name = name;
}
public string Name { get; set; }
public int QuestionsAnswered { get; set; }
public int CorrectAnswers { get; set; }
public string LetterGrade => GetLetterGrade();
private string GetLetterGrade()
{
if (QuestionsAnswered == 0) return "N/A";
var percent = CorrectAnswers / QuestionsAnswered * 100;
if (percent < 60) return "F";
if (percent < 63) return "D-";
if (percent < 67) return "D";
if (percent < 70) return "D+";
if (percent < 73) return "C-";
if (percent < 77) return "C";
if (percent < 80) return "C+";
if (percent < 83) return "B-";
if (percent < 87) return "B";
if (percent < 90) return "B+";
if (percent < 90) return "A-";
if (percent < 97) return "A";
return "A+";
}
}
This seems like a lot of work, but if you're going to ask a lot of questions, it will save time in the end by reducing duplicated code and encapsulating functionality in separate classes and methods. Adding new features will be easier, too.
To use these classes, we can simply instantiate a new Quiz class, pass it a User, populate the QuizItems, and then call BeginTest:
private static void Main()
{
Console.Write("Please enter your name: ");
var userName = Console.ReadLine();
var quiz = new Quiz(new User(userName));
PopulateQuizItems(quiz);
quiz.BeginTest();
GetKeyFromUser("\nDone!! Press any key to exit...");
}
I put the code to populate the quiz items in a separate method, in order to reduce the clutter in the Main method. Right now it just has your single question:
private static void PopulateQuizItems(Quiz quiz)
{
if (quiz == null) return;
quiz.QuizItems.Add(new QuizItem
{
Question = "What does the word 'virile' mean?",
PossibleAnswers = new List<string>
{
"Like a rabbit",
"Like a man",
"Like a wolf",
"Like a horse"
},
CorrectAnswerIndex = 1,
DisplayCorrectAnswerImmediately = true
});
}
Then it looks something like this:

C# NullReferenceException Thrown: My StudentList static class array is null

I have been trying to figure out what is happening with my code. I wrote an application where the user is able to enter marks of the student through a GUI application. The first form shows options, the next form is to enter the student information (name, number, mark), and the last form is to display a summary of the student information (total number of students, highest mark, lowest mark, name of student with highest mark, list of students).
To store all the student entries, I had made a student class. I created a static Student array and placed it in my ProgramFunctions class file (which is all static methods).
When I try to run the form which displays the student summary, thats where it crashes - If I look at the Auto's tab, it tells me the value of student[a] is null (I made use of a for loop to go through each student object in the array). I did trace through the adding of students and it does show that I have added new entries to the Student array.
Exceptions would be thrown at my calculation methods (highestMark, lowestMark, average). Here is my code:
class ProgramFunctions
{
private static Student[] studentList = new Student[25];
private static int counter = 0;
public static void addNewStudent(Student newStudent)
{
if (studentList.Count() == counter)
{
MessageBox.Show("The Student List is Full", "List is Full");
}
else
{
studentList[counter] = newStudent;
counter++;
}
}
public static void displayErrorMessage(String message, String title)
{
MessageBox.Show(message, title);
}
public static TextBox validateTextBox(int textboxNumber, TextBox thisTextBox)
{
if (textboxNumber.Equals(1)) //Student Name textbox
{
if (thisTextBox.Text.Length < 0 || thisTextBox.Text.Length > 100)
{
displayErrorMessage("The Student Name specified is out of allowed region (greater than 100 or less than 0 characters. Please fix this", "Student Name Error");
}
else
{
thisTextBox.Text = thisTextBox.Text.Trim();
return thisTextBox;
}
}
else if (textboxNumber.Equals(2)) //Student number text box (only 10 characters allowed)
{
if (thisTextBox.Text.Length < 0 || thisTextBox.Text.Length > 10)
{
displayErrorMessage("The student number you specified is greater than 10 characters or less than 0. Please fix this", "Student Number Error");
}
else
{
thisTextBox.Text = thisTextBox.Text.Trim();
return thisTextBox;
}
}
else
{
if (thisTextBox.Text.Length > 2 || thisTextBox.Text.Length < 0)
{
displayErrorMessage("Invalid Length for exam mark", "Invalid Exam Mark");
}
else
{
thisTextBox.Text = thisTextBox.Text.Trim();
return thisTextBox;
}
}
return null;
}
public static int getMaximumMarkPosition()
{
int highestMark = -999;
int positionFound = -1;
for (int a = 0; a < counter; a++)
{
if (studentList[a].getExamMark > highestMark)
{
highestMark = studentList[a].getExamMark; //This is where the error would occur
positionFound = a;
}
}
return positionFound;
}
public static int getHighestMark(int position)
{
return studentList[position].getExamMark;
}
public static int getLowestMark(int position)
{
return studentList[position].getExamMark;
}
public static string getHighestStudentMarkName(int position)
{
return studentList[position].getStudentName;
}
public static int getLowestMarkPosition()
{
int lowestMark = 999;
int positionFound = -1;
int studentMark = 0;
for (int a = 0; a < studentList.Count(); a++)
{
studentMark = studentList[a].getExamMark; //This is where the error would occur
if (studentMark < lowestMark)
{
lowestMark = studentMark;
positionFound = a;
}
}
return positionFound;
}
public static double calculateClassAverage()
{
double sum = 0;
double average = 0;
for (int a = 0; a < studentList.Count(); a++)
{
sum = sum + studentList[a].getExamMark;
}
average = sum / studentList.Count();
return average;
}
public static int getTotalNumberOfStudents()
{
return counter;
}
public static RichTextBox getTextBoxData(RichTextBox thisTextBox)
{
thisTextBox.Text = "STUDENT MARK DATA: \n\n";
for (int a = 1; a < studentList.Count(); a++)
{
Student currentStudent = returnStudentInformation(a);
thisTextBox.Text = thisTextBox.Text + "\n" + currentStudent.getStudentName + "\t\t" + currentStudent.getExamMark + "\t" + currentStudent.getStudentNumber;
}
return thisTextBox;
}
public static Student returnStudentInformation(int index)
{
return studentList[index];
}
}
}
It seems to me that if the student list isn't full accessing any index at counter or higher will result in a null object. I would suggest only looping up to counter:
for (int a = 1; a < counter; a++)
{
Student currentStudent = returnStudentInformation(a);
thisTextBox.Text = thisTextBox.Text + "\n" + currentStudent.getStudentName + "\t\t" + currentStudent.getExamMark + "\t" + currentStudent.getStudentNumber;
}
All this begs the question why use a static array for dynamic data when List<T> is available and is made for dynamic data.

Program to find minimum number in string

I have a c# class like so
internal class QueuedMinimumNumberFinder : ConcurrentQueue<int>
{
private readonly string _minString;
public QueuedMinimumNumberFinder(string number, int takeOutAmount)
{
if (number.Length < takeOutAmount)
{
throw new Exception("Error *");
}
var queueIndex = 0;
var queueAmount = number.Length - takeOutAmount;
var numQueue = new ConcurrentQueue<int>(number.ToCharArray().Where(m => (int) Char.GetNumericValue(m) != 0).Select(m=>(int)Char.GetNumericValue(m)).OrderBy(m=>m));
var zeroes = number.Length - numQueue.Count;
while (queueIndex < queueAmount)
{
int next;
if (queueIndex == 0)
{
numQueue.TryDequeue(out next);
Enqueue(next);
} else
{
if (zeroes > 0)
{
Enqueue(0);
zeroes--;
} else
{
numQueue.TryDequeue(out next);
Enqueue(next);
}
}
queueIndex++;
}
var builder = new StringBuilder();
while (Count > 0)
{
int next = 0;
TryDequeue(out next);
builder.Append(next.ToString());
}
_minString = builder.ToString();
}
public override string ToString() { return _minString; }
}
The point of the program is to find the minimum possible integer that can be made by taking out any x amount of characters from a string(example 100023 is string, if you take out any 3 letters, the minimum int created would be 100). My question is, is this the correct way to do this? Is there a better data structure that can be used for this problem?
First Edit:
Here's how it looks now
internal class QueuedMinimumNumberFinder
{
private readonly string _minString;
public QueuedMinimumNumberFinder(string number, int takeOutAmount)
{
var queue = new Queue<int>();
if (number.Length < takeOutAmount)
{
throw new Exception("Error *");
}
var queueIndex = 0;
var queueAmount = number.Length - takeOutAmount;
var numQueue = new List<int>(number.Where(m=>(int)Char.GetNumericValue(m)!=0).Select(m=>(int)Char.GetNumericValue(m))).ToList();
var zeroes = number.Length - numQueue.Count;
while (queueIndex < queueAmount)
{
if (queueIndex == 0)
{
var nextMin = numQueue.Min();
numQueue.Remove(nextMin);
queue.Enqueue(nextMin);
} else
{
if (zeroes > 1)
{
queue.Enqueue(0);
zeroes--;
} else
{
var nextMin = numQueue.Min();
numQueue.Remove(nextMin);
queue.Enqueue(nextMin);
}
}
queueIndex++;
}
var builder = new StringBuilder();
while (queue.Count > 0)
{
builder.Append(queue.Dequeue().ToString());
}
_minString = builder.ToString();
}
public override string ToString() { return _minString; }
}
A pretty simple and efficient implementation can be made, once you realize that your input string digits map to the domain of only 10 possible values: '0' .. '9'.
This can be encoded as the number of occurrences of a specific digit in your input string using a simple array of 10 integers: var digit_count = new int[10];
#MasterGillBates describes this idea in his answer.
You can then regard this array as your priority queue from which you can dequeue the characters you need by iteratively removing the lowest available character (decreasing its occurrence count in the array).
The code sample below provides an example implementation for this idea.
public static class MinNumberSolver
{
public static string GetMinString(string number, int takeOutAmount)
{
// "Add" the string by simply counting digit occurrance frequency.
var digit_count = new int[10];
foreach (var c in number)
if (char.IsDigit(c))
digit_count[c - '0']++;
// Now remove them one by one in lowest to highest order.
// For the first character we skip any potential leading 0s
var selected = new char[takeOutAmount];
var start_index = 1;
selected[0] = TakeLowest(digit_count, ref start_index);
// For the rest we start in digit order at '0' first.
start_index = 0;
for (var i = 0; i < takeOutAmount - 1; i++)
selected[1 + i] = TakeLowest(digit_count, ref start_index);
// And return the result.
return new string(selected);
}
private static char TakeLowest(int[] digit_count, ref int start_index)
{
for (var i = start_index; i < digit_count.Length; i++)
{
if (digit_count[i] > 0)
{
start_index = ((--digit_count[i] > 0) ? i : i + 1);
return (char)('0' + i);
}
}
throw new InvalidDataException("Input string does not have sufficient digits");
}
}
Just keep a count of how many times each digit appears. An array of size 10 will do. Count[i] gives the count of digit i.
Then pick the smallest non-zero i first, then pick the smallest etc and form your number.
Here's my solution using LINQ:
public string MinimumNumberFinder(string number, int takeOutAmount)
{
var ordered = number.OrderBy(n => n);
var nonZero = ordered.SkipWhile(n => n == '0');
var zero = ordered.TakeWhile(n => n == '0');
var result = nonZero.Take(1)
.Concat(zero)
.Concat(nonZero.Skip(1))
.Take(number.Length - takeOutAmount);
return new string(result.ToArray());
}
You could place every integer into a list and find all possible sequences of these values. From the list of sequences, you could sort through taking only the sets which have the number of integers you want. From there, you can write a quick function which parses a sequence into an integer. Next, you could store all of your parsed sequences into an array or an other data structure and sort based on value, which will allow you to select the minimum number from the data structure. There may be simpler ways to do this, but this will definitely work and gives you options as far as how many digits you want your number to have.
If I'm understanding this correctly, why don't you just pick out your numbers starting with the smallest number greater than zero. Then pick out all zeroes, then any remaining number if all the zeroes are picked up. This is all depending on the length of your ending result
In your example you have a 6 digit number and you want to pick out 3 digits. This means you'll only have 3 digits left. If it was a 10 digit number, then you would end up with a 7 digit number, etc...
So have an algorithm that knows the length of your starting number, how many digits you plan on removing, and the length of your ending number. Then just pick out the numbers.
This is just quick and dirty code:
string startingNumber = "9999903040404"; // "100023";
int numberOfCharactersToRemove = 3;
string endingNumber = string.Empty;
int endingNumberLength = startingNumber.Length - numberOfCharactersToRemove;
while (endingNumber.Length < endingNumberLength)
{
if (string.IsNullOrEmpty(endingNumber))
{
// Find the smallest digit in the starting number
for (int i = 1; i <= 9; i++)
{
if (startingNumber.Contains(i.ToString()))
{
endingNumber += i.ToString();
startingNumber = startingNumber.Remove(startingNumber.IndexOf(i.ToString()), 1);
break;
}
}
}
else if (startingNumber.Contains("0"))
{
// Add any zeroes
endingNumber += "0";
startingNumber = startingNumber.Remove(startingNumber.IndexOf("0"), 1);
}
else
{
// Add any remaining numbers from least to greatest
for (int i = 1; i <= 9; i++)
{
if (startingNumber.Contains(i.ToString()))
{
endingNumber += i.ToString();
startingNumber = startingNumber.Remove(startingNumber.IndexOf(i.ToString()), 1);
break;
}
}
}
}
Console.WriteLine(endingNumber);
100023 starting number resulted in 100 being the end result
9999903040404 starting number resulted in 3000044499 being the end result
Here's my version to fix this problem:
DESIGN:
You can sort your list using a binary tree , there are a lot of
implementations , I picked this one
Then you can keep track of the number of the Zeros you have in your
string Finally you will end up with two lists: I named one
SortedDigitsList and the other one ZeroDigitsList
perform a switch case to determine which last 3 digits should be
returned
Here's the complete code:
class MainProgram2
{
static void Main()
{
Tree theTree = new Tree();
Console.WriteLine("Please Enter the string you want to process:");
string input = Console.ReadLine();
foreach (char c in input)
{
// Check if it's a digit or not
if (c >= '0' && c <= '9')
{
theTree.Insert((int)Char.GetNumericValue(c));
}
}
//End of for each (char c in input)
Console.WriteLine("Inorder traversal resulting Tree Sort without the zeros");
theTree.Inorder(theTree.ReturnRoot());
Console.WriteLine(" ");
//Format the output depending on how many zeros you have
Console.WriteLine("The final 3 digits are");
switch (theTree.ZeroDigitsList.Count)
{
case 0:
{
Console.WriteLine("{0}{1}{2}", theTree.SortedDigitsList[0], theTree.SortedDigitsList[1], theTree.SortedDigitsList[2]);
break;
}
case 1:
{
Console.WriteLine("{0}{1}{2}", theTree.SortedDigitsList[0], 0, theTree.SortedDigitsList[2]);
break;
}
default:
{
Console.WriteLine("{0}{1}{2}", theTree.SortedDigitsList[0], 0, 0);
break;
}
}
Console.ReadLine();
}
}//End of main()
}
class Node
{
public int item;
public Node leftChild;
public Node rightChild;
public void displayNode()
{
Console.Write("[");
Console.Write(item);
Console.Write("]");
}
}
class Tree
{
public List<int> SortedDigitsList { get; set; }
public List<int> ZeroDigitsList { get; set; }
public Node root;
public Tree()
{
root = null;
SortedDigitsList = new List<int>();
ZeroDigitsList = new List<int>();
}
public Node ReturnRoot()
{
return root;
}
public void Insert(int id)
{
Node newNode = new Node();
newNode.item = id;
if (root == null)
root = newNode;
else
{
Node current = root;
Node parent;
while (true)
{
parent = current;
if (id < current.item)
{
current = current.leftChild;
if (current == null)
{
parent.leftChild = newNode;
return;
}
}
else
{
current = current.rightChild;
if (current == null)
{
parent.rightChild = newNode;
return;
}
}
}
}
}
//public void Preorder(Node Root)
//{
// if (Root != null)
// {
// Console.Write(Root.item + " ");
// Preorder(Root.leftChild);
// Preorder(Root.rightChild);
// }
//}
public void Inorder(Node Root)
{
if (Root != null)
{
Inorder(Root.leftChild);
if (Root.item > 0)
{
SortedDigitsList.Add(Root.item);
Console.Write(Root.item + " ");
}
else
{
ZeroDigitsList.Add(Root.item);
}
Inorder(Root.rightChild);
}
}

Categories