Array.Sort   zodpovězená otázka

VB.NET, Algoritmy, .NET

Dobrý den,

snažím se setřídit pole tříd.

Třída má vlastnosti norma(string),velikost(byte),šířka(single)

Nejprve potřebuji setřídit pole podle norem(string) k tomu použiji:

Array.Sort(sortKeyString,pole)

(sortKeyString je pole stringů vytažené z pole tříd)

To se setřídí vpořádku.

Poté chci seřadit každou normu podle velikosti(byte)

najdu si startovní index, lenght index každé normy a přes cyklus setřídit druhou část.

Array.Sort(sortkey, doors, startindex, indexOfLenght)

V mém případě jsou string normy dvě

V prvním cyklu se pole s první normou seřadí správně

hodnoty metody jsou:

Array.Sort((15(lenght),33(lenght),0(start index),15(lenght))

Při druhém pruchodu cyklem jsou hodnoty:

Array.Sort((18(lenght),33(lenght),15(start index),18(lenght))

a tady mi to vypíše chybu:

Posun a délka jsou mimo hranice pole, nebo počet je větší než počet prvků počítaný od idexu po konec zdrojové kolekce.

Nevím kde by mohla být chyba délka klíče a délka řazené části pole jsou si rovné 18 = 18, start index je také v pořádku a součet start indexu a délky řazené části nepřekročí celkovou velikost pole. (při druhém průchodu 15 + 18 = 33)

Věděl by někdo kde dělám chybu ?

Celý třídíci kód:

Private Sub sortArrayDoor()
    Dim index As Integer = 0
    Dim sortKeyString(0) As String
    Dim poleNorem() As String

    'ziska pole stringu s normamy - OK
    For Each prvek As clsDoor In doors
        ReDim Preserve sortKeyString(index)
        sortKeyString(index) = prvek.Norma
        index += 1
    Next prvek
    'Setřídí celé pole podle norem - OK
    Array.Sort(sortKeyString, doors)

    'Funkce načte stringové pole norem {CSN,DIN} - OK
    poleNorem = clsHledani.HledejDvere(doors)

    'Cyklus pro setřídění části pole se stejnou normou
    For i As Integer = 0 To UBound(poleNorem)
        index = 0
        Dim startindex As Integer = startIndexNormy(doors,poleNorem(i))
        Dim stopindex As Integer = stopIndexNormy(doors, poleNorem(i))
        Dim indexOfLenght As Integer = lenghtIndex(doors, poleNorem(i))

        Dim sortkey(0) As Byte
        'Vyhledání sort key k cyklu - OK
        For j As Integer = startindex To stopindex
            ReDim Preserve sortkey(index)
            sortkey(index) = doors(j).Velikost_Ramecku
            index += 1
        Next j

        'Při druhém průchodu neprojde
        Array.Sort(sortkey, doors, startindex, indexOfLenght)
            'Array.Sort(sortkey, doors, startindex, indexOfLenght)
        Next i
    End Sub





    'Nalezení start indext - OK
    Private Function startIndexNormy(ByVal pole() As clsDoor, ByVal Norma As String) As Integer
        For i As Integer = 0 To UBound(pole)
            If pole(i).Norma = Norma Then
                Return i
            End If
        Next i
    End Function

    'Nalezeni stop indexu - OK
    Private Function stopIndexNormy(ByVal pole() As clsDoor, ByVal norma As String) As Integer
        Dim index As Integer = 0
        Dim nalezeno As Boolean = False
        For i As Integer = 0 To UBound(pole)
            If pole(i).Norma = norma Then
                If Not nalezeno Then
                    index = i
                    nalezeno = True
                End If
                index += 1
            End If
        Next i
        Return index - 1
    End Function

    'Vypočet lenght indexu - OK
    Private Function lenghtIndex(ByVal pole() As clsDoor, ByVal norma As String) As Integer
        Dim index As Integer = 0
        For i As Integer = 0 To UBound(pole)
            If pole(i).Norma = norma Then
                index += 1
            End If
        Next i
        Return index
    End Function

nahlásit spamnahlásit spam -1 / 1 odpovědětodpovědět

Tak se omlouvám chyba je v nepochopení metody array.sort

array.sort(klíč,pole,start index,lenght index)

indexy se určují na klíč, přičemž klíč musí mít délku celého pole.

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Možná budu psát z cesty, protože se přiznám, že jsem Váš kód moc nestudoval.

Pokud Vám ale jde o to, co jste popsal v prvních řádcích svého dotazu (setřídit pole instancí Vaší vlastní třídy), pak si myslím, že je jednodušší cestou nadefinovat si svůj vlastní comparer a setřídit pole standardními nástroji, které VB nabízí.

Takový jednoduchý nástin jednoho z mnoha možných řešení (vypadá to sice dlouhé, ale 2/3 kódu jsou tam jenom z důvodu možnosti vyzkoušení funkčnosti):

Public Class Sortovani
    ' Vaše pole
    Private pole(9) As MojeTrida


    Private Sub Sortovani_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        ' toto nemá s kódem nic společného, pouze si naplním cvičné pole
        ' náhodnými hodnotami
        Dim nahoda As New Random

        For i As Integer = 0 To 9
            Dim text As String = ""
            Dim vel As Byte = 0
            Dim sir As Single = 0

            For j As Integer = 0 To 1
                text &= Char.ConvertFromUtf32(Char.ConvertToUtf32("A", 0) + nahoda.Next(0, 2))
            Next
            pole(i) = New MojeTrida(text, nahoda.Next(0, 4), nahoda.Next(0, 5))
        Next

        ' opět nemá s kódem nic společného
        ' pouze pro kontrolu vytisknu obsah pole do textboxu1
        With Me.TextBox1
            .Text = ""
            For i As Integer = 0 To 9
                .Text &= i & vbTab & pole(i).norma & vbTab & pole(i).velikost & vbTab & pole(i).sirka & vbCrLf
            Next
        End With


    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        ' tímto příkazem seřadím své pole
        ' v druhém parametru odkazuji na funkci, ve které si nadefinuji algoritmus řazení
        Array.Sort(pole, AddressOf Porovnej)

        ' opět nemá s kódem nic společného
        ' pouze si opět pro kontrolu vypisuji obsah "setříděného" pole do textboxu2
        With Me.TextBox2
            .Text = ""
            For i As Integer = 0 To 9
                .Text &= i & vbTab & pole(i).norma & vbTab & pole(i).velikost & vbTab & pole(i).sirka & vbCrLf
            Next
        End With

    End Sub

    ''' <summary>
    ''' Funkce definující algoritmus třídění
    ''' </summary>
    ''' <param name="x"></param>
    ''' <param name="y"></param>
    ''' <returns>Vrací 1, pokud je x > y, -1 pokud je x mensi nez y a 0, pokud je x = y </returns>
    ''' <remarks></remarks>
    Public Function Porovnej(ByVal x As MojeTrida, ByVal y As MojeTrida) As Integer
       
        ' nejprve porovnam dle normy
        If x.norma > y.norma Then
            Return 1
        ElseIf x.norma < y.norma Then
            Return -1
        Else
            ' je-li norma stejná, porovnám dle velikosti
            If x.velikost > y.velikost Then
                Return 1
            ElseIf x.velikost < y.velikost Then
                Return -1
            Else
                ' je-li norma i velikost stejná, porovnám dle sirky
                If x.sirka > y.sirka Then
                    Return 1
                ElseIf x.sirka < y.sirka Then
                    Return -1
                End If
            End If
        End If
        ' pokud prošlo až sem, jsou všechny porovnávané veličiny stejné, proto vracím 0
        Return 0
    End Function

End Class



' zkrácený příklad Vaší třídy
Public Class MojeTrida
    ' pro jednoduchost mám proměnné cvičně Public (nemusím psát propetry)
    Public norma As String
    Public velikost As Byte
    Public sirka As Single

    Public Sub New(ByVal norm As String, ByVal vel As Byte, ByVal sir As Single)
        norma = norm
        velikost = vel
        sirka = sir
    End Sub

End Class

Z celého dlouhého příkladu je pro Vás funkční vlastně pouze ta metoda

Array.Sort(pole, AddressOf Porovnej)

a funkce "Porovnej". Vše ostatní je jen obalující balast.

nahlásit spamnahlásit spam 2 / 2 odpovědětodpovědět

A ještě jedno vylepšení.

Doporučil bych ještě v tom algoritmu pro porovnání ten první stupeň porovnávání nahradit standardním Comparerem, protože tak se dá jednoduše nastavit necitlivost takovéhoto porovnávání na velikost písmen (jedná se o řetězec), takže lepší by bylo použít:

' ...
' ...
' nejprve porovnam dle normy
        Dim i As Integer = String.Compare(x.norma, y.norma, True)
        If i <> 0 Then
            Return i
        Else
            ' je-li norma stejná, porovnám dle velikosti
            If x.velikost > y.velikost Then
' ...
' ...

nahlásit spamnahlásit spam 2 / 2 odpovědětodpovědět

Nedalo mi to a kouknul jsem se na ten Váš kód.

I kdyby byl náhodou funkční (jako že není), používáte tam, pro mne několik nepochopitelných postupů (nebo spíš ne zrovna efektivních):

1) Velice často používáte v cyklu příkaz pro změnu velikosti pole

ReDim...

není to zrovna ideální postup, protože tato metoda má dost velkou režii (pole se nedá jednoduše "zvětšit", proto tato metoda vlastně vytvoří pole nové (a protože používáte Preserve do něj zkopíruje obsah pole původního), no a pokud to děláte stále dokola, pěkně plácáte paměť.

Dále samostatnými funkcemi počítáte startovní a koncové indexy + délku indexového pole a přitom v každé funkci procházíte jednotlivé prvky pole.

Pominu-li, že délku indexového pole je možno zjistit, odečtete-li koncový index od počátečního, nebylo by lepší toto všechno dělat jednou funkcí - jinak totiž procházíte v každé funkci znovu a znovu své pole, a v případě, že bude obsahovat trochu více prvků, tak to taky nebude časově ideální.

A algoritmus řazení také nebude patřit k těm nejrychlejším - nejprve si z pole vytahujete klíčové prvky pro řazení a to jeno proto, abyste je zpátky použil pro řazení celého pole, no a s těmi indexy dále, i kdybyste to upravil tak, aby to vyhovovalo Vaší funkcionalitě, tak to bude hooodně složité a ještě více pomalé.

Doporučuji tedy podívat se na funkce řazení, které má v sobě VB již přímo zabudován - viz třeba můj příklad výše).

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Tento kód funguje (jen se musí správně udělat array.sort - ten v příkladu nebyl dobře, řazení proběhne jak má, změnu velikosti pole pomocí redim preserve používám protože pole nikdy nebude delší než 100 prvků. Třída je také velmi jednoduchá(jen pár vlastností).

Ale ano máte pravdu takto to není časově přiliš efektivní.

nahlásit spamnahlásit spam 0 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.
  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:
Heslo:

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback