1

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);
            }
        }
    }
}
9
  • 1
    In order to sort something, you have to somehow define the order. With single numbers it's obvious, but with objects you have to say how the parts come together to define the order. Have you defined such a function? Commented Jun 9, 2016 at 10:30
  • Your teacher wants you to write bubble sort, so you cannot use Array.Sort anyway Commented Jun 9, 2016 at 10:31
  • "I do that [bubble sort] all fine on an Array containing one dimension" So let's see that. Commented Jun 9, 2016 at 10:32
  • 1
    @MaciejLos: No it doesn't. It could implement IEquatable, which isn't the same thing, or a different class could implement IEqualityComparer... or the OP could pass in a comparison delegate, as they actually are doing... Commented Jun 9, 2016 at 10:37
  • 2
    @MaciejLos: (Actually, I missed the fact that you would use IComparer and IComparable, not IEqualityComparer/IEquatable at all, for sorting...) Commented Jun 9, 2016 at 10:48

1 Answer 1

2

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:

  1. soda should be named Soda. Classes should start with a capital letter (except maybe private nested ones).
  2. Use properties instead of methods for Drink_name, Drink_price, Drink_type etc. and better yet, use autoimplemented properties to reduce boilerplate code.
  3. 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.
  4. If you insist on keeping Drink use camel casing and remove _: DrinkName, DrinkType, etc.
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for the help I am getting closer to my solution and have to thursday lunch on me to solve my problems.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.