Numeryczne sortowanie stringów

0

Witam,

mam taką zagwozdkę. Piszę program, w którym między innymi znajduje się moduł z podstawowymi danymi z faktur.
Dane wyświetlane są za pomocą DataGridView, w połączeniu z bazą SQL.

Problem polega na sortowaniu po numerach faktur, których postać wygląda np tak - "123/2012/RK"
Numer faktury zapisany jest więc ciągiem znaków, a chciałbym sortować go numerycznie, np od najnowszych do najstarszych.
W praktyce wynikiem miałaby być lista faktur posortowanych zarówno wg numeru jak i rocznika (za slashem). Np:
3/2013/RK
2/2013/RK
1/2013/RK
1189/2012/RK
1188/2012/RK
...

Bardzo proszę o podpowiedzi, nie wiem jak to ugryźć.

0

przekonwertuj sobie odpowiednie części stringa na int i wtedy według nich posortuj

0

123/2012/RK to jest id tabeli????? jako text? Jeżeli tak to trochę babola popełniłeś.

0

123/2012/RK to oczywiście przykładowa wartość komórki, string

chyba zrobię jak mówi kolega Sopelek - szukałem jakiegoś innego rozwiązania ale chyba tylko to pozostaje

0

dodaj sobie 2 kolumny typu int: rok i numer ustaw je jako klucz główny tabeli. a pełny numer możesz konstruować w zapytaniu, trzymać w bazie, robić w kodzie itp itd.

0

Przykład gdy liczba występuję tylko na początku stringa .

 


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

enum Wynik
{
    rowny,
    mniejszy,
    wiekszy
};


namespace algorytmsortowania
{
    class Program
    {
        


        public static Wynik porownaj_Stringi(string w1, string w2)
        {
           
            int w1_liczba = 0; 
            int w1_liczba_liter = 0;
            if(!int.TryParse(w1,out w1_liczba))
            {
                w1_liczba_liter = LiczbaLiterOdKonca(w1);
                w1_liczba=int.Parse(w1.Substring(0,w1.Length-w1_liczba_liter));
            }


            

            int w2_liczba = 0;
            int w2_liczba_liter =0;
            if (!int.TryParse(w2, out w2_liczba))
            {
                w2_liczba_liter = LiczbaLiterOdKonca(w2);
                w2_liczba = int.Parse(w2.Substring(0, w2.Length - w2_liczba_liter));
            }
            

            if (w1_liczba == w2_liczba)
            {
                string w1_litery = w1.Substring(w1.Length - 1 - w1_liczba_liter);
                string w2_litery = w2.Substring(w2.Length - 1 - w2_liczba_liter);

                if (w1_litery.CompareTo(w2_litery) > 0)
                {
                    return Wynik.wiekszy;
                }
                else if (w1_litery.CompareTo(w2_litery) < 0)
                {
                    return Wynik.mniejszy;
                }
                else
                {
                    return Wynik.rowny;
                }
                
            }
            else if (w1_liczba > w2_liczba)
            {
                return Wynik.wiekszy;
            }
            else
            {
                return Wynik.mniejszy;
            }





        }

        public  static int LiczbaLiterOdKonca(string wyraz)
        {
            int licznik = 0;
            for (int i = wyraz.Length - 1; i >= 0; i--)
            {
                if (wyraz[i] >= '0' && wyraz[i] <= '9')
                {
                    break;
                }
                licznik++;
            }

            return licznik;
        }

        public static void QuickSort(string[] array, int left, int right)
        {
            var i = left;
            var j = right;
            var pivot = array[(left + right) / 2];
            while (i < j)
            {

                while (porownaj_Stringi(array[i].Substring(array[i].LastIndexOf(@"\")+1), pivot.Substring(pivot.LastIndexOf(@"\")+1)) == Wynik.mniejszy) i++;
                while (porownaj_Stringi(array[j].Substring(array[i].LastIndexOf(@"\")+1), pivot.Substring(pivot.LastIndexOf(@"\")+1)) == Wynik.wiekszy) j--;
                if (i <= j)
                {
                    // swap
                    var tmp = array[i];
                    array[i++] = array[j];  // ++ and -- inside array braces for shorter code
                    array[j--] = tmp;
                }
                if (left < j) QuickSort(array, left, j);
                if (i < right) QuickSort(array, i, right);
            }
        }

        public static void Main(string[] args)
        {
            string[] test = { @"\1", @"\2" ,@"\3" ,@"\4","5" ,"6", "6a", "6b", "6c", "10", "11", "12a", "12ab" };
            try
            {
                QuickSort(test, 0, test.Length - 1);
                foreach (var a in test)
                {
                    Console.WriteLine(a);
                }
                Console.WriteLine("koniec");
            }
            catch (FormatException e)
            {
                Console.WriteLine("Błędny format nazwy pliku");
            }
            finally
            {
                Console.ReadLine();
            }

        }


    }

}

 
0

Panowie @Ciekawski oraz @dam1en, autor pytał o sortowanie danych, nie o ich trzymanie w bazie. ;)

@zidu89, kompletnie nie kumam powyższego kodu. Co on właściwie robi? Mógłbyś jakieś diagramy UML do niego zamieścić?

@shao, wydaje mi się, że jeśli chcemy porównać numery faktur, to należy porównać numery faktur, a nie jakieś tam stringi.

Dlatego potrzebujemy klasy, która nam ten numer opisze:

class InvoiceNumber
{
    public int Year { get; private set; }
    public int Number { get; private set; }
    public string Code { get; private set; }
    private string numberAsText;

    public InvoiceNumber(string numberAsText)
    {
        this.numberAsText = numberAsText;
        string[] temp = numberAsText.Split('/');
        this.Number = int.Parse(temp[0]);
        this.Year = int.Parse(temp[1]);
        this.Code = temp[0];
    }

    public override string ToString()
    {
        return this.numberAsText;
    }
}

Jak rozumiem numer faktury składa się z roku, kolejnego numeru w roku oraz jakiegoś literowego kodu. Sparsowanie tego jest banalne, wystarczy funkcją Split podzielić stringa na trzy części, a potem je odpowiednio skonwertować do liczb (dla roku i numeru).

Samo sortowanie najwygodniej chyba zrealizować przez OrderBy z LINQ, np. tak:

var input = new[] {"1189/2012/RK", "2/2013/RK", "3/2013/RK", "1188/2012/RK", "1/2013/RK"};

var invoiceNumbers = new List<InvoiceNumber>();
foreach (var ś in input)
{
    invoiceNumbers.Add(new InvoiceNumber(ś));
}

var sorted = invoiceNumbers.OrderBy(ó => ó.Year).ThenBy(ź => ź.Number);

foreach (var ó in sorted)
{
    Console.WriteLine(ó);
}
0

jeszcze prościej jest założyć, że numer ma stałą ilość cyfr (np 5) i przy zapisywaniu numeru uzupełniać go z przodu spacjami. Na liście w gridzie może być ze spacjami, przy wyszukiwaniu pobierasz od usera bez spacji, uzupełniasz i szukasz. Jest to o tyle prostsze, że nie musisz nic konwertować przy odczycie z bazy
I jeszcze przykład
3/2013/RK
2/2013/RK
1/2013/RK
1189/2012/RK
1188/2012/RK

0

@somekind UML porównania bez QuickSorta ;p był to przykład napisania własnego sortowania ;)

Rysunek1.jpg

1

Jak chcesz to posortować w pamięci to rozbij pole na k pod-pól i sortuj wg kilku.

Powinieneś posortować w kolejności:

  • rok
  • nr faktury

Na mainframe można to zrobić bez rozbijania pola :) - o ile stosuje się stałoszerokościowe pole
http://www.mainframegurukul.com/srcsinc/drona/programming/languages/jcl/jcl.sort.html

1 użytkowników online, w tym zalogowanych: 0, gości: 1