无法对包含对象的Array进行排序。 C#

时间:2016-06-09 10:26:51

标签: c# arrays sorting

我正在开展一个学校项目,我花了5个小时试图了解如何使用包含四个维度的对象对数组进行排序。我打算做的是按productCodedrinkName对它们进行排序。当我阅读各种线程时,人们告诉OP使用LINQ。我不应该使用它,并且我越来越困惑使用什么方法。我被老师告知,使用冒泡排序(糟糕的算法,我知道),我在包含一个维度的数组上做得很好。我尝试Array.Sort然后获得System.InvalidOperationException

我疯了,即使我读了很多关于这个问题的主题,我也陷入困境。我可能以错误的方式使用ToString。任何推动都将不胜感激。

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);
            }
        }
    }
}

----------------------编辑--------------- 感谢您的帮助,我越来越接近我的解决方案,并且必须在我周日午餐时解决我的问题。

我的排序仍有问题;

//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;
            }
        }
    }
}

当我想要所有那些对产品组都是真实的时,我的线性搜索只返回一个值。我在Run()中尝试了一些不同的东西,以便更快地进行实验。我将附加当前代码。

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);
            }
        }
    }
}

1 个答案:

答案 0 :(得分:2)

为了对给定类型的对象进行排序,您需要知道如何比较两个对象开始。您可以对一组数字进行排序,因为您知道如何将122-10隔开等等。

您的代码中没有任何地方定义两个soda(顺便说一句应该是Soda)如何相互比较。在c#(和一般的.NET)中执行此操作的一种方法是使您的类实现一个名为IComparable<T>的非常特定的接口:

public interface IComparable<T>
{
    int CompareTo(T other);
}

CompareTo是排序算法,如Array.Sort或Linq&#39; OrderBy使用(如果没有另行说明)。你需要做同样的事情。 T是一种通用类型,在您的情况下,您有兴趣将苏打水与苏打水进行比较,因此T将为Soda

.NET中的CompareTo约定如下:

  • 如果this等于other,则返回0
  • 如果this小于other,则返回-1
  • 如果this大于other返回1
  • null被认为小于任何非null值。

您的实现必须遵循此约定才能使内置排序算法正常工作。

首先,您需要定义 您希望soda进行比较的方式。按名字?按价格?一切似乎都是合乎逻辑如果您的问题指定 soda应该如何比较,那么相应地实施比较逻辑,否则选择合理的选项。

我按名称订购,所以我要做以下事情:

public class Soda: IComparable<Soda>
{
    ....
    public int CompareTo(Soda other)
    {
        if (ReferenceEquals(other, null))
           return 1;

        return drinkName.CompareTo(other.drinkName);
    }
}

因为string实现了IComparable<string>,所以实现我自己的比较逻辑非常简单。

好的,现在sodas知道如何相互比较,像Array.Sort这样的东西将完美无缺。您自己的冒泡排序算法也应该运行良好,现在您已知道如何比较软饮料了。

另一种选择是实现IComparer<T>,它基本上是一个知道如何比较两个Soda的对象。调查一下,虽然在你的情况下我认为实施IComparable<T>是一个更清洁的解决方案。

在另一个页面上,您可以并且应该对代码进行一些改进:

  1. soda应命名为Soda。类应该以大写字母开头(可能是私有嵌套的)。
  2. 使用属性代替Drink_nameDrink_priceDrink_type等方法,更好的是,使用自动实现的属性来减少样板代码。
  3. 删除Drink表单属性名称,该类名为Soda,因此Drink非常多余,不添加任何有用信息;它无缘无故地让财产名称更长。
  4. 如果您坚持让Drink使用骆驼套管并移除_DrinkNameDrinkType