[GELÖST] Structure Spalte ohne SpaltenNamen übergeben

Anfängerfragen zum Programmieren mit PureBasic.
Benutzeravatar
GlassJoe
Beiträge: 108
Registriert: 11.06.2017 20:25
Computerausstattung: 2 x AMD Phenom II x4 945,2x Dell Latitude X300, Dell Latitude D410, Hp Compaq NC4400

[GELÖST] Structure Spalte ohne SpaltenNamen übergeben

Beitrag von GlassJoe »

Hi :)

Also seit gestern weis ich endlich ^^ das mann LinkedLists & Arrays auch als Parameter übergeben kann (hab das warscheinlich irgendwann mal ausprobiert gehabt, bei einer Version nach PB 4.20 und wusste nichts vom List Schlüsselwort, und hab dann bestimmt aufgegeben :mrgreen: ) da dachte ich mir.

Hey schreib ich mir doch endlich eine Prozedure (oder noch besser ein Module, Danke an mk-soft für den Denk anstoss :)) damit ich es nicht wie die letzten 8 Jahre mache und mir bei jedem neuen Tool eine ewig umständliche & sich wiederholende Prozedure schreibe, die mir GadgetColumns ausliest und in Structure Felder auftrennt und die Linked List nach FeldXY sortiert ^^

Naja sehr viel hat es mir nicht gebracht.....bis heute Morgen um 4 :mrgreen:

Als ich endlich rausgefunden habe das sowas geht

Code: Alles auswählen

  SortStructuredList(Animals(),#PB_Sort_Ascending,ColToSort,ColType)
Und ich mir diese ewig lange Zeile (die ich immer per F1 aus der Hilfe hole und dann anpasse :D )
die ich mir nicht merken kann

Code: Alles auswählen

SortStructuredList(Animals(), #PB_Sort_Ascending, OffsetOf(Animal\Name$), TypeOf(Animal\Name$))
sparen kann ! Das Offset kann ich direkt mit der Spalten Position ersetzen, und TypeOf da nehme ich einfach den Wert von #PB_String oder #PB_Integer, je nachdem wie es grade benötigt wird.

Aber das OffsetOf wecklassen, funzt komischerweise nicht immer ! Einmal gibt es einen Speicherfehler, und einmal nicht.

Und das ist nicht mal mein Haupt Problem, ich finde einfach keine Möglichkeit, eine Variable
zu füllen, ohne den expliziten Namen angeben zu müssen.

Siehe Zeile 118 | Da bräuchte ich es das erste mal, daß ich in

blabla_1$

den Inhalt von

InList.stuff()\s0

kriege, ohne dessen Namen direkt anzugeben, sondern die Spalte. (es muss doch einen Weg geben !)

Also muss ich auf die umständliche Methode zurück greifen, daß ich erst mal den Inhalt der
entsprechenden Spalte in der Repeat Schleife in

InList.stuff()\onlyS_for_sort_struc

schreibe, damit ich dann später blabla_1$ damit füllen kann.

Code: Alles auswählen

  
  Structure stuff
    s0.s
    s1.s
    s2.s
    s3.s
    s4.s
    Pos.i
    onlyS_for_sort_struc.s 
    onlyI_for_sort_struc.i 
  EndStructure
  
  Structure Animal
    Name$
    Speed.l
  EndStructure
  
  Global NewList Temp.stuff()
  
  Global NewList Animals.Animal() 
  AddElement(Animals())
  Animals()\Name$ = "Tiger"
  Animals()\Speed = 10
  
  AddElement(Animals())
  Animals()\Name$ = "Jaguar"
  Animals()\Speed = 40
  
  AddElement(Animals())
  Animals()\Name$ = "Zebra"
  Animals()\Speed = 30
  
  Procedure DuppeFillStruc(List InList.stuff())
    
    Debug "------FILL STRUC LIST------------------"
    
    ClearList(InList.stuff())
    
    AddElement(InList.stuff())
    InList.stuff()\s0 = "AAA0"
    InList.stuff()\s1 = "AAA1"
    InList.stuff()\s2 = "1"
    
    AddElement(InList.stuff())
    InList.stuff()\s0 = "BBB0"
    InList.stuff()\s1 = "BBB1"
    InList.stuff()\s2 = "2"
    
    AddElement(InList.stuff())
    InList.stuff()\s0 = "CCC0"
    InList.stuff()\s1 = "CCC1"
    InList.stuff()\s2 = "3"
    
    AddElement(InList.stuff())
    InList.stuff()\s0 = "CCC0"
    InList.stuff()\s1 = "CCC1"
    InList.stuff()\s2 = "3"
    
    AddElement(InList.stuff())
    InList.stuff()\s0 = "DDD0"
    InList.stuff()\s1 = "DDD1"
    InList.stuff()\s2 = "4" 
    
    ForEach InList.stuff()
      Debug InList.stuff()\s0
      Debug InList.stuff()\s1
      Debug InList.stuff()\s2
      Debug "---"
    Next
    
    Debug "-----DONE-----"
    
  EndProcedure
  
  Procedure DuppeKillStruc(SortOrder,List InList.stuff(),TypeString,ColToSort)
    
    Debug ""
    Debug "------SORT AND REM DUPES-------"
    
    If TypeString
      ColType = 8 ; #PB_SORT_STRING BZW #PB_STRING
    Else
      ColType = 21 ; #PB_SORT_INTEGER BZW #PB_INTEGER 
    EndIf
    
    tmp_max = ListSize(InList.stuff())
    
    If tmp_max > 1
      
      If TypeString
        
        ForEach InList.stuff()
          
          ;[/ REPEATING CRAP
          If ColToSort = 0
            InList.stuff()\onlyS_for_sort_struc = InList.stuff()\s0
          EndIf 
          If ColToSort = 1
            InList.stuff()\onlyS_for_sort_struc = InList.stuff()\s1
          EndIf 
          If ColToSort = 2
            InList.stuff()\onlyS_for_sort_struc = InList.stuff()\s2
          EndIf 
          If ColToSort = 3
            InList.stuff()\onlyS_for_sort_struc = InList.stuff()\s3
          EndIf 
          If ColToSort = 4
            InList.stuff()\onlyS_for_sort_struc = InList.stuff()\s4
          EndIf  
          ;]
          
        Next
        
        SortStructuredList(InList(),SortOrder,ColToSort,ColType) 
        
        ;SortStructuredList(InList(),SortOrder,OffsetOf(stuff\onlyS_for_sort_struc),ColType) 
        
        FirstElement(InList.stuff()) : blabla_1$ = InList.stuff()\onlyS_for_sort_struc : len1=Len(blabla_1$)
        NextElement(InList.stuff()) : blabla_2$ = InList.stuff()\onlyS_for_sort_struc : len2=Len(blabla_2$) 
        For tmp_p = 0 To tmp_max -1 
          If len1=len2 
            If FindString(blabla_1$,blabla_2$,1) = 1
              DeleteElement(InList.stuff())
              Debug "DEL => A="+blabla_1$+" B="+blabla_2$ 
            EndIf 
          EndIf 
          blabla_1$ = InList.stuff()\onlyS_for_sort_struc : len1=Len(blabla_1$) 
          If NextElement(InList.stuff()) = 0
            Break
          EndIf 
          blabla_2$ = InList.stuff()\onlyS_for_sort_struc : len2=Len(blabla_2$) 
        Next 
        
      Else 
        
        ForEach InList.stuff()
          
          ;[/ REPEATING CRAP
          If ColToSort = 0
            InList.stuff()\onlyI_for_sort_struc.i = Val(InList.stuff()\s0)
          EndIf 
          If ColToSort = 1
            InList.stuff()\onlyI_for_sort_struc.i = Val(InList.stuff()\s1)
          EndIf 
          If ColToSort = 2
            InList.stuff()\onlyI_for_sort_struc.i = Val(InList.stuff()\s2)
          EndIf 
          If ColToSort = 3
            InList.stuff()\onlyI_for_sort_struc.i = Val(InList.stuff()\s3)
          EndIf 
          If ColToSort = 4
            InList.stuff()\onlyI_for_sort_struc.i = Val(InList.stuff()\s4)
          EndIf
          ;]
          
        Next
        
        SortStructuredList(InList(),SortOrder,ColToSort,ColType)
        
        ; SortStructuredList(InList(),SortOrder,OffsetOf(stuff\onlyI_for_sort_struc.i),ColType) 
        
        FirstElement(InList.stuff()) : blabla_1 = InList.stuff()\onlyI_for_sort_struc.i
        NextElement(InList.stuff()) : blabla_2 = InList.stuff()\onlyI_for_sort_struc.i
        For tmp_p = 0 To tmp_max -1 
          If blabla_1=blabla_2
            DeleteElement(InList.stuff())
            Debug "DEL => A="+blabla_1+" B="+blabla_2 
          EndIf 
          blabla_1 = InList.stuff()\onlyI_for_sort_struc.i
          If NextElement(InList.stuff()) = 0
            Break
          EndIf 
          blabla_2 = InList.stuff()\onlyI_for_sort_struc.i
        Next 
        
      EndIf 
      
    EndIf 
    
    Debug "--DONE--------------"
    
    Debug ""
    Debug "--DEBUG--"
    ForEach InList.stuff()
      Debug InList.stuff()
      Debug InList.stuff()\s0
    Next 
    
  EndProcedure 
  
  Procedure SortThisCrap()
    
    ColToSort = 0 
    
    If ColToSort = 0
      ColType = #PB_String
    Else
      ColType = #PB_Long
    EndIf 
    
    Debug "--------------SORT Animal Name----------------------------"
    
    SortStructuredList(Animals(),#PB_Sort_Ascending,ColToSort,ColType)
    
    ForEach Animals()
      Debug Animals()\Name$+" - Speed: "+Str(Animals()\Speed)
    Next
    
    Debug "---"
    
    ColToSort = 1
    
    If ColToSort = 0
      ColType = #PB_String
    Else
      ColType = #PB_Long
    EndIf 
    
    Debug "--------------SORT Animal Speed----------------------------"
    
    SortStructuredList(Animals(),#PB_Sort_Ascending,ColToSort,ColType)
    
    ForEach Animals()
      Debug Animals()\Name$+" - Speed: "+Str(Animals()\Speed)
    Next
    
  EndProcedure
  
  DuppeFillStruc(Temp.stuff())
  
  DuppeKillStruc(#PB_Sort_Ascending,Temp.stuff(),#False,1) ; Geht immer
  ;DuppeKillStruc(#PB_Sort_Ascending,Temp.stuff(),#True,1) ; Speicherfehler wenn Zeile drüber auskommentiert ist. Wieso ?
  
  ; Hier geht es doch ! Egal ob 211 und/oder 212 auskommentiert sind 
  SortThisCrap()


ps: Ich weis Dank NicTheQuick das mann mit einer Map, viel schneller und speicherschonender Doppelte Einträge killen kann (b.z.w gar nicht erst in die Map aufnehmen) nur hab ich mir verdammt viel Code Schnipsel über die Jahre erstellt, die ich mir gerne mit der Methode die ich probiert habe anpassen würde.

ps2: Ja der DuppeKiller löscht natürlich im ersten Moment falsch, weil ich in Zeile 231
TypeString auf #False setze und dann Strings mit Buchstaben aus Spalte 1 zu Values umwandeln lasse.
Was natürlich immer dafür sorgt das es viele Werte mit 0 gibt, und dann gibts halt vieles Doppelte.

Den Speicherfehler gibt es wenn ich TypeString auf #True setze !

Siehe Kommentare im Code unten.
Zuletzt geändert von GlassJoe am 05.07.2017 01:03, insgesamt 1-mal geändert.
https://www.geek.com/tech/a-commodore-6 ... s-1672510/
٩(̾●̮̮̃̾•̃̾)۶ __̴ı̴̴̡̡̡ ̡͌l̡̡̡ ̡͌l̡*̡̡ ̴̡ı̴̴̡ ̡̡͡|̲̲̲͡͡͡ ̲▫̲͡ ̲̲̲͡͡π̲̲͡͡ ̲̲͡▫̲̲͡͡ ̲|̡̡̡ ̡ ̴̡ı̴̡̡ ̡͌l̡̡̡̡.___٩(- ̮̮̃-̃)۶
Benutzeravatar
mhs
Beiträge: 224
Registriert: 11.01.2009 16:30
Wohnort: Graben
Kontaktdaten:

Re: Structured LinkedList - Spalte ohne SpaltenNamen übergeb

Beitrag von mhs »

sparen kann ! Das Offset kann ich direkt mit der Spalten Position ersetzen.
Wie kommst du denn darauf? OffsetOf ermitteln der Offsetwert der Speicheradresse, also die Bits, die zwischen den Positionen liegen.

Dein 0, 1, 2, 3, 4 ist also grundlegend falsch! Schau dir mal OffsetOf in der Hilfe, sowie als Debugausgabe an und versuch zu verstehen was du falsch machst, dann wirst du auch schnell herausfinden, warum du einen Speicherfehler bei SortStructuredList() hast.

Um es ewas einzugrenzen, dein Fehler ist hier zu sehen:

Code: Alles auswählen

        ForEach InList.stuff()
         
          ;[/ REPEATING CRAP
          If ColToSort = 0
            InList.stuff()\onlyI_for_sort_struc.i = Val(InList.stuff()\s0)
          EndIf
          If ColToSort = 1
            InList.stuff()\onlyI_for_sort_struc.i = Val(InList.stuff()\s1)
          EndIf
          If ColToSort = 2
            InList.stuff()\onlyI_for_sort_struc.i = Val(InList.stuff()\s2)
          EndIf
          If ColToSort = 3
            InList.stuff()\onlyI_for_sort_struc.i = Val(InList.stuff()\s3)
          EndIf
          If ColToSort = 4
            InList.stuff()\onlyI_for_sort_struc.i = Val(InList.stuff()\s4)
          EndIf
          ;]
         
        Next
       
        SortStructuredList(InList(),SortOrder,ColToSort,ColType)
Außerdem solltest du darauf verzichten bei jedem Zugriff auf deine Liste InList, den Typ .stuff mit anzugeben... der wird nur bei der Deklaration oder bei den Funktionsparametern mit angegeben.
und TypeOf da nehme ich einfach den Wert von #PB_String oder #PB_Integer, je nachdem wie es grade benötigt wird
Das ist soweit ok, aber dann würde ich auch die Konstante nehmen und nicht den tatsächlichen Wert... also nicht wie hier:

Code: Alles auswählen

If TypeString
      ColType = 8 ; #PB_SORT_STRING BZW #PB_STRING
    Else
      ColType = 21 ; #PB_SORT_INTEGER BZW #PB_INTEGER
    EndIf
Michael Hack

Michael Hack Software :: Softwareentwicklung | Webentwicklung | IT-Dienstleistungen
www.michaelhacksoftware.de :: www.mh-s.de :: www.michael-hack.de
Benutzeravatar
GlassJoe
Beiträge: 108
Registriert: 11.06.2017 20:25
Computerausstattung: 2 x AMD Phenom II x4 945,2x Dell Latitude X300, Dell Latitude D410, Hp Compaq NC4400

Re: Structured LinkedList - Spalte ohne SpaltenNamen übergeb

Beitrag von GlassJoe »

mhs hat geschrieben:
sparen kann ! Das Offset kann ich direkt mit der Spalten Position ersetzen.
Wie kommst du denn darauf? OffsetOf ermitteln der Offsetwert der Speicheradresse, also die Bits, die zwischen den Positionen liegen.

Dein 0, 1, 2, 3, 4 ist also grundlegen falsch! Schau dir mal OffsetOf in der Hilfe, sowie als Debugausgabe an und versuch zu verstehen was du falsch machst, dann wirst du auch schnell herausfinden, warum du einen Speicherfehler hast.
Weil ich es einfach ausprobiert habe ? Und das Ding macht unter

SortThisCrap()

genau das was es soll, also bin ich davon ausgegangen das alles Ok ist !

Und das Geschreibe unter Offset macht mich kein bisschen schlauer :D
Da ich 0 Ahnung von irgendwelchen Bits habe ! Bin kein Assemblerianer :mrgreen:

Die Hilfe ist an vielen Stellen sehr gut, aber an manchen auch nicht, der List Befehl zum übergeben von Lists als Parameter steht nicht im Linked List Inhaltsverzeichniss (sonst hätte es schon wesentlich früher entdeckt) sondern irgendwo mittendrin beim NewList Befehl (PB 5.24 LTS) und das nicht mal in anklickbarer Form. Wenn mann es dort nicht sieht, weil mann die Hilfe von NewList nach paar Jahren gewiss nicht mehr aufruft, muss schon der Zufall mitspielen damit mann es findet.

Um es ewas einzugrenzen, dein Fehler ist hier zu sehen:

Code: Alles auswählen

        ForEach InList.stuff()
         
          ;[/ REPEATING CRAP
          If ColToSort = 0
            InList.stuff()\onlyI_for_sort_struc.i = Val(InList.stuff()\s0)
          EndIf
          If ColToSort = 1
            InList.stuff()\only_for_sort_struc.i = Val(InList.stuff()\s1)
          EndIf
          If ColToSort = 2
            InList.stuff()\onlyI_for_sort_struc.i = Val(InList.stuff()\s2)
          EndIf
          If ColToSort = 3
            InList.stuff()\onlyI_for_sort_struc.i = Val(InList.stuff()\s3)
          EndIf
          If ColToSort = 4
            InList.stuff()\onlyI_for_sort_struc.i = Val(InList.stuff()\s4)
          EndIf
          ;]
         
        Next
       
        SortStructuredList(InList(),SortOrder,ColToSort,ColType)
Ich sehe da keinen Fehler ! Ich erwähne es noch mal es stürzt ab wenn ich SortType auf #PB_String setze !
und TypeOf da nehme ich einfach den Wert von #PB_String oder #PB_Integer, je nachdem wie es grade benötigt wird
Das ist soweit ok, aber dann würde ich auch die Konstante nehmen und nicht den tatsächlichen Wert... also nicht wie hier:

Code: Alles auswählen

If TypeString
      ColType = 8 ; #PB_SORT_STRING BZW #PB_STRING
    Else
      ColType = 21 ; #PB_SORT_INTEGER BZW #PB_INTEGER
    EndIf
Ich nehme aber TypeString weil ich eben nicht TypeOf(Struktur\Feld) angeben muss !

Und nicht angeben will !

Du Hast keine Lösung für das eigentliche Problem vorgeschlagen, hast es anscheinend überlesen was ich mir seit jahren bei jedem Tool mit Sortier Funktion/HeaderSortEvents ohne Ausnahme antun muss, nur damit ich GadgetColumn 0-5 (das ist ja noch wenig, teils hab ich 20 Cols) auslesen,sortieren & wieder zurück schreiben kann.

Ich will nicht den expliziten Namen von einem ListenFeld angeben müssen (also bringt mit TypeOf erst mal gar nichts, und SizeOf auch nicht) sondern ungefähr sowas

ColToSort = 2
blabla_1$ = ListenName()\[ColToSort]

Wobei das [2] für die Spalte steht mit der blabla_1$ gefüllt wird.

Es muss doch eine Möglichkeit geben eine

Col 0-4 Bearbeitung einer Structurierten Liste mit Col Angabe als Parameter in einer Prozedure ausführen zu lassen, ohne ewiges

If ColToSort = 0
InList.stuff()\onlyS_for_sort_struc = InList.stuff()\s0
EndIf
If ColToSort = 1
InList.stuff()\onlyS_for_sort_struc = InList.stuff()\s1
EndIf

oder ewiges Case
https://www.geek.com/tech/a-commodore-6 ... s-1672510/
٩(̾●̮̮̃̾•̃̾)۶ __̴ı̴̴̡̡̡ ̡͌l̡̡̡ ̡͌l̡*̡̡ ̴̡ı̴̴̡ ̡̡͡|̲̲̲͡͡͡ ̲▫̲͡ ̲̲̲͡͡π̲̲͡͡ ̲̲͡▫̲̲͡͡ ̲|̡̡̡ ̡ ̴̡ı̴̡̡ ̡͌l̡̡̡̡.___٩(- ̮̮̃-̃)۶
Benutzeravatar
mhs
Beiträge: 224
Registriert: 11.01.2009 16:30
Wohnort: Graben
Kontaktdaten:

Re: Structured LinkedList - Spalte ohne SpaltenNamen übergeb

Beitrag von mhs »

Weil ich es einfach ausprobiert habe ? Und das Ding macht unter

SortThisCrap()

genau das was es soll, also bin ich davon ausgegangen das alles Ok ist !
Bist du dir da sicher? Ich hab es nicht überprüft, aber allein vom anschauen des Codes würde ich sagen, dass das Sortierergebnis nach Speed nicht stimmen kann. Er erzeugt nur keinen Speicherfehler, weil du dort bei der zweiten Spalte nach einem Long sortieren lässt.
Und das Geschreibe unter Offset macht mich kein bisschen schlauer :D
Da ich 0 Ahnung von irgendwelchen Bits habe ! Bin kein Assemblerianer :mrgreen:
Ein paar Grundlagen wie ein PC funktioniert mit seinen Bits und Bytes können aber nicht schaden.

Ich wollte dir einen Hinweis geben, dass du z.B. die Ausgabe der Funktion OffsetOf() prüfen könntest, z.B. so:

Code: Alles auswählen

debug OffsetOf(stuff\s0)
debug OffsetOf(stuff\s1)
debug OffsetOf(stuff\s2)
debug OffsetOf(stuff\s3)
Dann würde dir nämlich auffallen, dass dort nicht 0, 1, 2, 3, 4, ... als Ergebnis kommt, sondern 0, 8, 16, 24, ... bei 64bit bzw. 0, 4, 8, 12, ... bei 32bit. Das bedeutet für dich, dass du bei SortStructuredList() nicht 0, 1, 2, ... übergeben darfst, auch wenn du OffsetOf() nicht nutzen möchtest.
Ich nehme aber TypeString weil ich eben nicht TypeOf(Struktur\Feld) angeben muss !
Da hast du mich wohl falsch verstanden, ich meinte, dass du statt des Wertes direkt die Konstante verwenden sollst. So wie du es machst, den Wert zu verwenden und dann den Konstantennamen im Kommentar zu schreiben macht einfach keinen Sinn und ist nur eine zusätzliche Fehlerquelle. So z.B:

Code: Alles auswählen

If TypeString
      ColType = #PB_String
Else
      ColType = #PB_Integer
EndIf
Du Hast keine Lösung für das eigentliche Problem vorgeschlagen, hast es anscheinend überlesen was ich mir seit jahren bei jedem Tool mit Sortier Funktion/HeaderSortEvents ohne Ausnahme antun muss, nur damit ich GadgetColumn 0-5 (das ist ja noch wenig, teils hab ich 20 Cols) auslesen,sortieren & wieder zurück schreiben kann.
Nein, das habe ich nicht überlesen, aber findest du es nicht sinnvoller erstmal die Fehler zu korrigieren? Ich wollte dir eine Hilfestellung geben, um die Probleme zu finden und selbst lösen zu können. Wenn ich dir die fertige Lösung hier hinklatsche wird dir das wenig bringen.

Nun zu deinem eigentlichen Problem, da du es aber nicht so mit Bits und Bytes hast, würde ich dir dafür ein Makro oder eine Funktion vorschlagen, die so aussehen könnte und tatsächlich einen Select case verwendet:

Code: Alles auswählen

Procedure.s getValue(List InList.stuff(), Col.i)

  Select Col
    Case 0: ProcedureReturn InList()\s0
    Case 1: ProcedureReturn InList()\s1
    Case 2: ProcedureReturn InList()\s2
    Case 3: ProcedureReturn InList()\s3
    Case 4: ProcedureReturn InList()\s4
  EndSelect
  
  ProcedureReturn ""

EndProcedure
Michael Hack

Michael Hack Software :: Softwareentwicklung | Webentwicklung | IT-Dienstleistungen
www.michaelhacksoftware.de :: www.mh-s.de :: www.michael-hack.de
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8809
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Structured LinkedList - Spalte ohne SpaltenNamen übergeb

Beitrag von NicTheQuick »

Wenn du nur Strings hast, geht es wesentlich einfacher, indem du ein statisches Array in der Struktur benutzt. Mit einem dynamischen geht es natürlich auch, wenn du zur Laufzeit die Anzahl an Spalten ändern willst. Im Grunde mache ich hier alles so wie du, nur wesentlich einfacher. Vor allem stürzt meine Funktion zum Löschen doppelter Einträge nicht ab, wenn nur ein Eintrag da ist, und sie verbraucht weniger Speicher und nur eine Hilfsvariable vom Typ Pointer. Ich muss also auch nicht Strings herum kopieren wie du es immer gemacht hast.

Code: Alles auswählen

EnableExplicit

Structure stuff
	s.s[5]
EndStructure

NewList daten.stuff()
Define.i i, j

; daten-Liste füllen und anzeigen
For i = 1 To 20
	If AddElement(daten())
		For j = 0 To 4
			daten()\s[j] = "Col" + j + "_" + Str(Random(5))
		Next j
	EndIf
Next

Procedure debugList(List l.stuff())
	Protected i.i, s.s
	
	ForEach l()
		s = ""
		For i = 0 To 4
			s + l()\s[i] + "  "
		Next
		Debug s
	Next
EndProcedure

Procedure Deduplicate(List inout.stuff(), column.i, typ.i = #PB_String, dir.i = #PB_Sort_Ascending)
	SortStructuredList(inout(), dir, column * SizeOf(String), typ)
				
	Protected *compare.stuff = FirstElement(inout())
	If *compare
		While NextElement(inout())
			If *compare\s[column] = inout()\s[column]
				DeleteElement(inout())
			Else
				*compare = @inout()
			EndIf
		Wend
	EndIf
	
EndProcedure

Debug "Original"
debugList(daten())

Deduplicate(daten(), 0)

Debug "Deduplicated (col 1)"
debugList(daten())
Benutzeravatar
mk-soft
Beiträge: 3855
Registriert: 24.11.2004 13:12
Wohnort: Germany

Re: Structured LinkedList - Spalte ohne SpaltenNamen übergeb

Beitrag von mk-soft »

Der Code von Nic ist schon super :allright:

Wenn man die Structure mit Align 8 erstellt kann man den Offset auch berechnen und über diesen den vergleich durchführen.

Habe mal den Code von Nic als Basis genommen...

Code: Alles auswählen

EnableExplicit

Structure stuff Align 8
  s.s[5]
  lval.l
  iVal.i
EndStructure

NewList daten.stuff()
Define.i i, j

; daten-Liste füllen und anzeigen
For i = 1 To 20
  If AddElement(daten())
    For j = 0 To 4
      daten()\s[j] = "Col" + j + "_" + Str(Random(5))
    Next j
    daten()\lval = Random(4)
    daten()\iVal = Random(3)
  EndIf
Next

Procedure debugList(List l.stuff())
  Protected i.i, s.s
  
  ForEach l()
    s = ""
    For i = 0 To 4
      s + l()\s[i] + "  "
    Next
    Debug s + "/ lVal=" + l()\lval + " / iVal=" + l()\iVal
  Next
EndProcedure

Procedure Deduplicate(List inout.stuff(), column.i, typ.i = #PB_String, dir.i = #PB_Sort_Ascending)
  Protected offset.i, *str1.String, *str2.String, *lVal1.Long, *lVal2.Long, *iVal1.Integer, *iVal2.Integer
  offset = column * 8 ; Align 8
  If offset => SizeOf(stuff)
    ; Fehler
    ProcedureReturn #False
  EndIf
  
  SortStructuredList(inout(), dir, offset, typ)
  
  Protected *compare = FirstElement(inout())
  If Not *compare
    ; Keine Elemente
    ProcedureReturn #False
  EndIf
  
  Select typ
    Case #PB_String
      *str1 = *compare + offset
      While NextElement(inout())
        *str2 = @inout() + offset
        If *str1\s = *str2\s
          DeleteElement(inout())
        Else
          *str1 = @inout() + offset
        EndIf
      Wend
      
    Case #PB_Long
      *lVal1 = *compare + offset
      While NextElement(inout())
        *lVal2 = @inout() + offset
        If *lVal1\l = *lVal2\l
          DeleteElement(inout())
        Else
          *lVal1 = @inout() + offset
        EndIf
      Wend
      
    Case #PB_Integer
      *iVal1 = *compare + offset
      While NextElement(inout())
        *iVal2 = @inout() + offset
        If *iVal1\i = *iVal2\i
          DeleteElement(inout())
        Else
          *iVal1 = @inout() + offset
        EndIf
      Wend
    
  EndSelect
  
EndProcedure

Debug "Original"
debugList(daten())

;Deduplicate(daten(), 0)
;Deduplicate(daten(), 5, #PB_Long)
Deduplicate(daten(), 6, #PB_Integer)

Debug "Deduplicated (col 1)"
debugList(daten())

Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Benutzeravatar
GlassJoe
Beiträge: 108
Registriert: 11.06.2017 20:25
Computerausstattung: 2 x AMD Phenom II x4 945,2x Dell Latitude X300, Dell Latitude D410, Hp Compaq NC4400

Re: Structured LinkedList - Spalte ohne SpaltenNamen übergeb

Beitrag von GlassJoe »

mhs hat geschrieben:
Weil ich es einfach ausprobiert habe ? Und das Ding macht unter

SortThisCrap()

genau das was es soll, also bin ich davon ausgegangen das alles Ok ist !
Bist du dir da sicher? Ich hab es nicht überprüft, aber allein vom anschauen des Codes würde ich sagen, dass das Sortierergebnis nach Speed nicht stimmen kann. Er erzeugt nur keinen Speicherfehler, weil du dort bei der zweiten Spalte nach einem Long sortieren lässt.
Und das Geschreibe unter Offset macht mich kein bisschen schlauer :D
Da ich 0 Ahnung von irgendwelchen Bits habe ! Bin kein Assemblerianer :mrgreen:
Ein paar Grundlagen wie ein PC funktioniert mit seinen Bits und Bytes können aber nicht schaden.

Ich wollte dir einen Hinweis geben, dass du z.B. die Ausgabe der Funktion OffsetOf() prüfen könntest, z.B. so:

Code: Alles auswählen

debug OffsetOf(stuff\s0)
debug OffsetOf(stuff\s1)
debug OffsetOf(stuff\s2)
debug OffsetOf(stuff\s3)
Dann würde dir nämlich auffallen, dass dort nicht 0, 1, 2, 3, 4, ... als Ergebnis kommt, sondern 0, 8, 16, 24, ... bei 64bit bzw. 0, 4, 8, 12, ... bei 32bit. Das bedeutet für dich, dass du bei SortStructuredList() nicht 0, 1, 2, ... übergeben darfst, auch wenn du OffsetOf() nicht nutzen möchtest.
Ich nehme aber TypeString weil ich eben nicht TypeOf(Struktur\Feld) angeben muss !
Da hast du mich wohl falsch verstanden, ich meinte, dass du statt des Wertes direkt die Konstante verwenden sollst. So wie du es machst, den Wert zu verwenden und dann den Konstantennamen im Kommentar zu schreiben macht einfach keinen Sinn und ist nur eine zusätzliche Fehlerquelle. So z.B:

Code: Alles auswählen

If TypeString
      ColType = #PB_String
Else
      ColType = #PB_Integer
EndIf
Du Hast keine Lösung für das eigentliche Problem vorgeschlagen, hast es anscheinend überlesen was ich mir seit jahren bei jedem Tool mit Sortier Funktion/HeaderSortEvents ohne Ausnahme antun muss, nur damit ich GadgetColumn 0-5 (das ist ja noch wenig, teils hab ich 20 Cols) auslesen,sortieren & wieder zurück schreiben kann.
Nein, das habe ich nicht überlesen, aber findest du es nicht sinnvoller erstmal die Fehler zu korrigieren? Ich wollte dir eine Hilfestellung geben, um die Probleme zu finden und selbst lösen zu können. Wenn ich dir die fertige Lösung hier hinklatsche wird dir das wenig bringen.

Nun zu deinem eigentlichen Problem, da du es aber nicht so mit Bits und Bytes hast, würde ich dir dafür ein Makro oder eine Funktion vorschlagen, die so aussehen könnte und tatsächlich einen Select case verwendet:

Code: Alles auswählen

Procedure.s getValue(List InList.stuff(), Col.i)

  Select Col
    Case 0: ProcedureReturn InList()\s0
    Case 1: ProcedureReturn InList()\s1
    Case 2: ProcedureReturn InList()\s2
    Case 3: ProcedureReturn InList()\s3
    Case 4: ProcedureReturn InList()\s4
  EndSelect
  
  ProcedureReturn ""

EndProcedure
Ich war mir sicher :D und die Werte die ich in einem Testfetzen benutzt hab, haben aus Zufall beim Long richtige Reifenfolge ergeben.

Ich habs nicht so mit Zahlen , Bits & Bytes :oops: alles was ich weis ist das ein 8-Bit 256 Zustände (und nicht mal da bin ich mir wirklich sicher :lol: ) haben kann :lol: und selbst bei den kürzesten Binärzahl Folgen bin ich schon überfordert :lol:

Ich dachte einfach falsch und einfach :mrgreen:

Das mann dort wo OffsetOf(Struktur\Feld) im SortStructuredList Befehl steht, einfach z.B Col1 angibt und dann auch Col 1 von der Structure benutzt wird. b.z.w Zahl 50 entspricht SpaltenID 50, 5 der ID5, 3 der ID3 usw

Bin nicht drauf gekommen, daß es anders ist.

Aber durch den Tip mit

Code: Alles auswählen

debug OffsetOf(stuff\s0)
debug OffsetOf(stuff\s1)
debug OffsetOf(stuff\s2)
debug OffsetOf(stuff\s3)
und dem Case Beispiel, hab ich mir was zurecht gebastelt, daß funzt :allright: so das ich endlich eine Prozedure für sowas basteln kann mit Liste & Spalte als Parameter übergabe :)

Danke :) :allright: :allright:

Code: Alles auswählen

  Structure Animal
    Name$
    Speed.l
    pp$
    mongo.i
  EndStructure
  
  Dim Animals.Animal(10)
  
  Animals(0)\Name$ = "Tiger"
  Animals(0)\Speed = 10
  Animals(0)\pp$ = "super3"
  Animals(0)\mongo = 300
  
  Animals(1)\Name$ = "Jaguar"
  Animals(1)\Speed = 40
  Animals(1)\pp$ = "super1"
  Animals(1)\mongo = 100
  
  Animals(2)\Name$ = "Zebra"
  Animals(2)\Speed = 30
  Animals(2)\pp$ = "super2"
  Animals(2)\mongo = 500

  Debug OffsetOf(Animal\Name$)
  Debug OffsetOf(Animal\Speed)
  Debug OffsetOf(Animal\pp$)
  Debug OffsetOf(Animal\mongo)
  
  ColToSort = 0
  Select ColToSort
    Case 0 : SortType = #PB_String : ColID = OffsetOf(Animal\Name$)
    Case 1 : SortType = #PB_Integer : ColID = OffsetOf(Animal\Speed)
    Case 2 : SortType = #PB_String : ColID = OffsetOf(Animal\pp$)
    Case 3 : SortType = #PB_String : ColID = OffsetOf(Animal\mongo) 
  EndSelect

  SortStructuredArray(Animals(),#PB_Sort_Ascending,ColID,SortType)
  
  For k=0 To 2
    Debug Animals(k)\Name$+" - Speed: "+Str(Animals(k)\Speed)+" - pp:"+Animals(k)\pp$+" - mongo: "+Str(Animals(k)\mongo)
  Next

Das SortType kann ich nicht wecklassen, und es mit TypeOf() ersetzen weil
es TypeOf erst seit 5.11 gibt, und ich will Code erstellen der teils runter bis PB 4.20 geht (desshalb kam oben auch Long vor, hab mir aus der Hilfe was zusammen kopiert ^^) und die Konstanten Kommentare hab ich drin gehabt weil bei irgendeiner PB 5.XX Version ja #PB_Sort_XY ersetzt wurde mit#PB_XY

@NicTheQuick

Hammer Code :allright: ich verstehe ihn nur grade nicht :lol: werde aber meinen DupeKiller Code austauschen gegen deinen. (wichtig ist nur das nicht z.B HalloFritz als Dupe erkannt wird, wenn das Such Wort Fritz ist)

Ich dachte Arrays mit mehreren Felden (ich hab Jahre lang nur linked Lists mit Structuren benutzt, und
keinen Vorteil an Arays erkannt, nur Nachteile weil weniger Funktionen, also hab ich sie eigentlich nie benötigt und benutzt) gehen nur so.

Code: Alles auswählen

  Structure Animal
    Name$
    Speed.l
    pp$
    mongo.i
  EndStructure
  
  Dim Animals.Animal(10)
  
  Animals(0)\Name$ = "Tiger"
  Animals(0)\Speed = 10
  Animals(0)\pp$ = "super3"
  Animals(0)\mongo = 300
  
  Animals(1)\Name$ = "Jaguar"
  Animals(1)\Speed = 40
  Animals(1)\pp$ = "super1"
  Animals(1)\mongo = 100
  
  Animals(2)\Name$ = "Zebra"
  Animals(2)\Speed = 30
  Animals(2)\pp$ = "super2"
  Animals(2)\mongo = 500
oder so

Code: Alles auswählen

  Dim MultiArray.b(NbColumns, NbLines)
  MultiArray(10, 20) = 10
  MultiArray(20, 30) = 20
was ich in der Hilfe gefunden habe, aber absolute 0 verstanden habe. Da nicht wirklich was dazu erklärt wird (und auch kein Beispiel dabei ist, wo sowas Sinn ergibt) und die Syntax für mich absolute keinen Sinn ergibt.

vl kann mir das ja einer erklären ? :shock:

Wo wird dort die 10 und die 20 drunter rein gesetzt ? in NbColumns ? Wenn ja, ist es doch völlig sinnlos, mehrere Spalten in Dim MultiArray angeben zu können, weil ich so nur die den Wert erste Spalte setzen kann, aber nicht die 2.

Beim auslesen dann selbe, hab den Monitor angestart, und mir nur gedacht ? Wie soll ich Bitte NbLines auslesen ?

Ich hab noch nie gesehen das links vom = 2 Variablen getrennt durch ein , stehen und das es dann keinen Syntax Error gibt (selbst wenn es ihn nicht gibt, bei mir im Kopf gibt es denn dann :lol: )

In deinem Code hast du oben folgendes stehen

Code: Alles auswählen

EnableExplicit

Structure stuff
   s.s[5]
EndStructure

NewList daten.stuff()

Also mit einer Zeile Code definierst du 5 Felder ? :shock: verdammt hätte ich doch nur früher gewusst das sowas geht :mrgreen: Gott was hätte ich mir Tip Arbeit und Stress gespart.

Ich verstehe zwar noch nicht wie s.s[5] funzt, b.z.w wo es in der Hilfe so drin steht das es auch Sinn ergibt, aber das werde ich schon noch :)

Jedenfalls Danke für den tollen Code :allright:

@mk-soft

Auch an dich ein fettes Danke :allright:

Ich weis nur noch nicht für was das Align steht und wieso ausgerechnett 8 (vl weil 8 die letzte SpaltenID in meinem ersten Post für OffsetOff wäre ?)

@PB-Handbuch Maker :mrgreen:

Noch ne Sache zur PB Hilfe.

Code: Alles auswählen

SortStructuredList(ListenName(), Optionen, OffsetOf(Struktur\Feld), TypeOf(Struktur\Feld) [, Start, Ende])
Mann kann also als 3 Parameter die direkte SpaltenID angeben nach der Sortiert werden soll wieso steht das nicht dran ?
Ein einziges Beispiel hätte gereicht, nicht jeder Mensch kann so abstrakt denken, und mit so einem komplizierten Satz zu OffsettOf

5.24
Offset des Feldes in der Struktur. OffsetOf() kann verwendet werden, um die Position eines Feldes in der dem Array zugewiesenen Struktur zu ermitteln, nach dem sortiert werden soll.
drauf kommen das mann so SortStructuredList flexibel benutzen kann, vor allem wenn da was von Array steht, dann denkt mann gleich das es nicht für Listen geht.

Ruft mann die Hilfe zu OffsetOff auf steht da folgendes

5.24
Syntax
Index = OffsetOf(Struktur\Feld)
Index = OffsetOf(Interface\Funktion())

Beschreibung

OffsetOf kann verwendet werden, um den Index eines Struktur-Feldes oder den Index einer Interface-Funktion herauszufinden. Bei der Verwendung mit einem Interface ist der Funktions-Index der Speicher-Offset, es gilt deshalb IndexOfTheFunction*SizeOf(Integer).
Beispiel

Structure Person
Name.s
Vorname.s
Alter.w
EndStructure

Debug OffsetOf(Person\Alter) ; wird 8 ergeben, da ein String(-Pointer) 4 Byte im Speicher belegt
; (16 mit dem 64 Bit Compiler, da ein String dort 8 Bytes belegt)


Interface ITest
Create()
Destroy(Flags)
EndInterface

Debug OffsetOf(ITest\Destroy()) ; wird 4 ergeben
Mann sieht das Schlagwort Structure ok, aber dann sieht mann Interfaces und denkt sich........öh kompliziert, ich Noob, Interfaces ist was für Profis, hier ist es bestimmt nicht.

Ein einziges
sehr nützlich zum sortieren von Structurierten Listen
in normalen Klammern hätte gereicht, und selbst ich Vollhorst :lol: hätte kapiert das ich richtig bin, und nicht den Faden verloren, weil der Satz zusätzlich zum Interface (daß einen abschreckt) noch

IndexOfTheFunction*SizeOf(Integer).

und

Speicher-Offset

enthält.

Wie soll mann anhand des Befehls Namen

Offset

drauf kommen was das überhaupt ist ? Bei fast jeden anderen PB Befehl kommt mann drauf was der Befehl tut, anhand der Bezeichnung. Aber etwas wie Offset wird im englischen Sprachgebrauch da drausen nie benutzt.

Und wenn ich im Hilfe Index nach OffsetOff suche, und es doppelklicke, ist das erste was im rechten Abteil sehe

die Erklärung zu SizeOff statt OffsetOff.

Es ist ganz leicht verwechselbar (vor allem wenn mann müde wie ich ist) und mann denkt sich

"Öh eine Funktion mit Size im Namen kann wird wohl ziehmlich warscheinlich nicht dafür zuständig sein, daß mann einen Spalten Wert oder eine ID übermittelt.

Ich wusste ja nicht mal was davon, weil ja in der SortStructuredList Hilfe nicht drin steht, daß mann als 3. Parameter nicht zwingend etwas mit dieser Syntax

OffsetOf(Animal\Name$)

angeben muss.

Das die Syntax auch

SortStructuredList(ListenName(), Optionen,FeldIDEinerStruktur,#PB_String)

sein kann.
https://www.geek.com/tech/a-commodore-6 ... s-1672510/
٩(̾●̮̮̃̾•̃̾)۶ __̴ı̴̴̡̡̡ ̡͌l̡̡̡ ̡͌l̡*̡̡ ̴̡ı̴̴̡ ̡̡͡|̲̲̲͡͡͡ ̲▫̲͡ ̲̲̲͡͡π̲̲͡͡ ̲̲͡▫̲̲͡͡ ̲|̡̡̡ ̡ ̴̡ı̴̡̡ ̡͌l̡̡̡̡.___٩(- ̮̮̃-̃)۶
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8809
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Structured LinkedList - Spalte ohne SpaltenNamen übergeb

Beitrag von NicTheQuick »

Mal ein kleines bisschen Hintergrundwissen für dich. Ich habe einfach alles in Quelltext gegossen, damit ich hier weniger Formatierungsaufwand im Forum habe.

Code: Alles auswählen

; Diese Struktur besteht aus drei Feldern unterschiedlicher Größe.
Structure Person
	; Ein String wird nicht direkt in der Struktur gespeichert, sondern
	; hier wird nur ein Pointer zu dem eigentlichen String im Speicher
	; vorgehalten. Das ist wichtig, da ein String eine variable Größe
	; haben kann, ein Pointer aber immer gleich groß ist. Auf einem
	; 64-Bit-System belegt er 8 Bytes (= 64 Bit) und auf einem 32-Bit-
	; System demnach 4 Bytes (= 32 Bit)
	name.s
	
	; Eine Ganzzahl vom Typ Ascii (.a) belegt immer genau ein Byte und
	; kann Werte zwischen 0 und 255 annehmen.
	alter.a
	
	; Eine Ganzzahl vom Typ Long (.l) belegt immer genau vier Bytes und
	; kann Werte zwischen -2147483648 und 2147483647 annehmen.
	plz.l
EndStructure

; Die Strukturgröße ist demnach genau 8 + 1 + 4 = 13 Bytes, wenn man
; die Datei als 64-Bit-Executable kompiliert.
Debug SizeOf(Person)

; OffsetOf() gibt nun die genaue Byte-Position in dieser Struktur zurück
; Person\name steht an der erste Stelle in der Struktur und ist deshalb
; genau 0
Debug OffsetOf(Person\name)

; Person\alter steht direkt hinter name, ist also um 8 Bytes versetzt
Debug OffsetOf(Person\alter)

; Und letztendlich gibt es dann noch Person\plz, was sich dahinter
; anschließt
Debug OffsetOf(Person\plz)

; SortStructeredList/Array benötigt nun dieses Offset und den Typ des
; Feldes, damit es an der richtigen Stelle der Struktur den Wert auslesen
; und vergleichen kann.

; Das ganze können wir auch simulieren mit OffsetOf() und PeekS/A/L().
; Dazu legen wir mal ein Element an.
Define.Person person
person\name = "NTQ"
person\alter = 31
person\plz = 12345

; Um das Alter ohne Angabe des Feldnamens auslesen zu können, benötigen
; wir das Offset von Person\alter und den Typ, der hier Ascii ist. Demnach
; kommen wir so an das Feld:
Debug PeekA(@person + 8)
;      Typ^     Offset^

; Genauso geht es dann auch mit der PLZ:
Debug PeekL(@person + 9)
;      Typ^     Offset^

; Mit dem String wird es etwas komplizierter, denn wir wissen ja jetzt,
; dass in der Struktur eigentlich nur der Pointer steht, der auf den
; eigentlichen Speicherbereich zeigt, in dem der String sich befindet.
; Um ihn auslesen zu können, ohne person\name zu benutzen, müssen wir
; den Pointer extrahieren und dann mit PeekS() den String auslesen.
Define *pointer = PeekI(@person + 0)
;                           Offset^
Debug *pointer
Debug PeekS(*pointer)
;      Typ^

; Einfach durchnummerieren statt OffsetOf() zu benutzen, ist also der
; falsche Weg, denn jedes Feld in einer Struktur hat ihr individuelles
; Offset, das von allen Feldern davor abhängt.

; Jetzt gibt es noch den Trick mit statischen Arrays. Dazu nehme ich
; eine neue Struktur:
Structure Personen5
	name.s[5]
EndStructure

; Hier lässt es Purebasic leider nicht zu einfach das Offset zu berechnen.
; Das hier geht also nicht: Debug OffsetOf(Personen5\name[0])
; Es ergibt einen Syntax-Error. Aber wir wissen ja, dass jedes dieser fünf
; Felder vom gleichen Typ ist und sie demnach in der Struktur im gleichen
; Abstand voneinandern stehen müssen. Dieser Abstand ist die Größe
; des Pointers, der auf die enthaltenen Strings zeigt. Und da ein
; Pointer immer so groß ist wie ein Integer, können wir die Größe mit
; SizeOf(Integer) erfahren. Damit es verständlicher wirkt, könnten wir
; aber auch einfach SizeOf(String) nehmen, denn die Struktur "String"
; ist auch immer so groß wie ein Pointer, da sie genau ein String-Feld
; enthält. Beweis:
Debug SizeOf(Integer)
Debug SizeOf(String)

; Möchten wir also wissen wie viele Felder unserer Struktur Personen5
; enthält, könnten wir rechnen und erhalten (natürlich) 5.
Debug SizeOf(Personen5) / SizeOf(String)

; Aber interessanter ist nun, wie wir die einzelnen Felder ansprechen
; können, ohne dass wir ihren Feldnamen wissen. Das hab ich in meiner
; Deduplicate-Procedure nämlich so gemacht.

; Legen wir uns zunächst mal eine Variable mit dieser Struktur an:
Define personen.Personen5

; Und füllen sie:
personen\name[0] = "NTQ"
personen\name[1] = "GlassJoe"
personen\name[2] = "mk-soft"
personen\name[4] = "mhs"

; Angenommen wir wollen das dritte Feld auslesen. Dann ist der Index
; 2, da wir bei 0 anfangen zu zählen:
*pointer = PeekI(@personen + 2 * SizeOf(String))
;                       Index^
Debug PeekS(*pointer)

; Ich habe das vierte Feld absichtlich nicht gefüllt. Denn hier muss
; man aufpassen. Sollte noch nie ein String zugewiesen worden sein,
; ist der Pointer ungültig, da er noch nirgendwo hinzeigt. Musste er
; ja auch nicht, denn es gibt noch keinen String, der irgendwo gespeichert
; werden sollte. Das sieht man hier:
*pointer = PeekI(@personen + 3 + SizeOf(String))

; Der Pointer scheint zwar nicht 0 zu sein, ...
Debug *pointer

; ...aber wenn wir versuchen darauf zuzugreifen, gibt es einen ungültigen
; Speicherzugriff.

;Debug PeekS(*pointer)
Vielleicht findest du damit ja selbst heraus, was "Align 8" macht. ;-)
Benutzeravatar
GlassJoe
Beiträge: 108
Registriert: 11.06.2017 20:25
Computerausstattung: 2 x AMD Phenom II x4 945,2x Dell Latitude X300, Dell Latitude D410, Hp Compaq NC4400

Re: Structured LinkedList - Spalte ohne SpaltenNamen übergeb

Beitrag von GlassJoe »

NicTheQuick hat geschrieben:Mal ein kleines bisschen Hintergrundwissen für dich. Ich habe einfach alles in Quelltext gegossen, damit ich hier weniger Formatierungsaufwand im Forum habe.

Code: Alles auswählen

; Diese Struktur besteht aus drei Feldern unterschiedlicher Größe.
Structure Person
	; Ein String wird nicht direkt in der Struktur gespeichert, sondern
	; hier wird nur ein Pointer zu dem eigentlichen String im Speicher
	; vorgehalten. Das ist wichtig, da ein String eine variable Größe
	; haben kann, ein Pointer aber immer gleich groß ist. Auf einem
	; 64-Bit-System belegt er 8 Bytes (= 64 Bit) und auf einem 32-Bit-
	; System demnach 4 Bytes (= 32 Bit)
	name.s
	
	; Eine Ganzzahl vom Typ Ascii (.a) belegt immer genau ein Byte und
	; kann Werte zwischen 0 und 255 annehmen.
	alter.a
	
	; Eine Ganzzahl vom Typ Long (.l) belegt immer genau vier Bytes und
	; kann Werte zwischen -2147483648 und 2147483647 annehmen.
	plz.l
EndStructure

; Die Strukturgröße ist demnach genau 8 + 1 + 4 = 13 Bytes, wenn man
; die Datei als 64-Bit-Executable kompiliert.
Debug SizeOf(Person)

; OffsetOf() gibt nun die genaue Byte-Position in dieser Struktur zurück
; Person\name steht an der erste Stelle in der Struktur und ist deshalb
; genau 0
Debug OffsetOf(Person\name)

; Person\alter steht direkt hinter name, ist also um 8 Bytes versetzt
Debug OffsetOf(Person\alter)

; Und letztendlich gibt es dann noch Person\plz, was sich dahinter
; anschließt
Debug OffsetOf(Person\plz)

; SortStructeredList/Array benötigt nun dieses Offset und den Typ des
; Feldes, damit es an der richtigen Stelle der Struktur den Wert auslesen
; und vergleichen kann.

; Das ganze können wir auch simulieren mit OffsetOf() und PeekS/A/L().
; Dazu legen wir mal ein Element an.
Define.Person person
person\name = "NTQ"
person\alter = 31
person\plz = 12345

; Um das Alter ohne Angabe des Feldnamens auslesen zu können, benötigen
; wir das Offset von Person\alter und den Typ, der hier Ascii ist. Demnach
; kommen wir so an das Feld:
Debug PeekA(@person + 8)
;      Typ^     Offset^

; Genauso geht es dann auch mit der PLZ:
Debug PeekL(@person + 9)
;      Typ^     Offset^

; Mit dem String wird es etwas komplizierter, denn wir wissen ja jetzt,
; dass in der Struktur eigentlich nur der Pointer steht, der auf den
; eigentlichen Speicherbereich zeigt, in dem der String sich befindet.
; Um ihn auslesen zu können, ohne person\name zu benutzen, müssen wir
; den Pointer extrahieren und dann mit PeekS() den String auslesen.
Define *pointer = PeekI(@person + 0)
;                           Offset^
Debug *pointer
Debug PeekS(*pointer)
;      Typ^

; Einfach durchnummerieren statt OffsetOf() zu benutzen, ist also der
; falsche Weg, denn jedes Feld in einer Struktur hat ihr individuelles
; Offset, das von allen Feldern davor abhängt.

; Jetzt gibt es noch den Trick mit statischen Arrays. Dazu nehme ich
; eine neue Struktur:
Structure Personen5
	name.s[5]
EndStructure

; Hier lässt es Purebasic leider nicht zu einfach das Offset zu berechnen.
; Das hier geht also nicht: Debug OffsetOf(Personen5\name[0])
; Es ergibt einen Syntax-Error. Aber wir wissen ja, dass jedes dieser fünf
; Felder vom gleichen Typ ist und sie demnach in der Struktur im gleichen
; Abstand voneinandern stehen müssen. Dieser Abstand ist die Größe
; des Pointers, der auf die enthaltenen Strings zeigt. Und da ein
; Pointer immer so groß ist wie ein Integer, können wir die Größe mit
; SizeOf(Integer) erfahren. Damit es verständlicher wirkt, könnten wir
; aber auch einfach SizeOf(String) nehmen, denn die Struktur "String"
; ist auch immer so groß wie ein Pointer, da sie genau ein String-Feld
; enthält. Beweis:
Debug SizeOf(Integer)
Debug SizeOf(String)

; Möchten wir also wissen wie viele Felder unserer Struktur Personen5
; enthält, könnten wir rechnen und erhalten (natürlich) 5.
Debug SizeOf(Personen5) / SizeOf(String)

; Aber interessanter ist nun, wie wir die einzelnen Felder ansprechen
; können, ohne dass wir ihren Feldnamen wissen. Das hab ich in meiner
; Deduplicate-Procedure nämlich so gemacht.

; Legen wir uns zunächst mal eine Variable mit dieser Struktur an:
Define personen.Personen5

; Und füllen sie:
personen\name[0] = "NTQ"
personen\name[1] = "GlassJoe"
personen\name[2] = "mk-soft"
personen\name[4] = "mhs"

; Angenommen wir wollen das dritte Feld auslesen. Dann ist der Index
; 2, da wir bei 0 anfangen zu zählen:
*pointer = PeekI(@personen + 2 * SizeOf(String))
;                       Index^
Debug PeekS(*pointer)

; Ich habe das vierte Feld absichtlich nicht gefüllt. Denn hier muss
; man aufpassen. Sollte noch nie ein String zugewiesen worden sein,
; ist der Pointer ungültig, da er noch nirgendwo hinzeigt. Musste er
; ja auch nicht, denn es gibt noch keinen String, der irgendwo gespeichert
; werden sollte. Das sieht man hier:
*pointer = PeekI(@personen + 3 + SizeOf(String))

; Der Pointer scheint zwar nicht 0 zu sein, ...
Debug *pointer

; ...aber wenn wir versuchen darauf zuzugreifen, gibt es einen ungültigen
; Speicherzugriff.

;Debug PeekS(*pointer)
Vielleicht findest du damit ja selbst heraus, was "Align 8" macht. ;-)
Danke :praise:

Das ist ne super Erklärung, so ergibt alles nenn Sinn.

Das einzige was ich beim durchlesen grade noch nicht verstanden habe ist

Code: Alles auswählen

*pointer = PeekI(@personen + 2 * SizeOf(String))
Weil sonst überall immer + Wert + vorgekommen ist...........grübel grade nach vl * weil jedes Statische String Feld den selben Byte Abstand voneinander hat ?

Hab grade die Hilfe von Align durchgelesen, mit deiner super Erklärung oben, hat es gleich von Anfang an Sinn ergeben :allright:
Nur für fortgeschrittene Anwender: Der optionale Align Parameter ermöglicht es, die Ausrichtung (englisch "Alignment") zwischen jedem Struktur-Feld einzustellen. Die standardmäßige Ausrichtung (auch Anordnung) ist 1, was keine Ausrichtung bedeutet. Zum Beispiel, wenn die Ausrichtugn auf 4 eingestellt wird, dann wird jedes Feld-Offset auf einer 4-Byte-Grenze liegen. Dies kann helfen, eine bessere Leistung beim Zugriff auf die Felder der Struktur zu erreichen. Aber es kann auch mehr Speicher benötigen, da etwas Platz zwischen den einzelnen Feldern verschwendet wird. Der besondere Wert #PB_Structure_AlignC kann verwendet werden, um die Struktur wie in der Sprache C auszurichten, nützlich beim Importieren von C-Strukturen für die Verwendung mit API-Funktionen.
Ich muss dann aufpassen, weil bei 64Bit die Grenzen bei 8Byte wären (bei einem statischen Aray) wenn ich mich nicht täusche.

Ich probiere auf jeden Fall aus, was mann machen kann in dem Fall :)
; Ich habe das vierte Feld absichtlich nicht gefüllt. Denn hier muss
; man aufpassen. Sollte noch nie ein String zugewiesen worden sein,
; ist der Pointer ungültig, da er noch nirgendwo hinzeigt. Musste er
; ja auch nicht, denn es gibt noch keinen String, der irgendwo gespeichert
; werden sollte. Das sieht man hier:
*pointer = PeekI(@personen + 3 + SizeOf(String))

; Der Pointer scheint zwar nicht 0 zu sein, ...
Debug *pointer

; ...aber wenn wir versuchen darauf zuzugreifen, gibt es einen ungültigen
; Speicherzugriff.
EDIT:

Eine Sache verstehe ich noch nicht (kommt auch in mk-soft seiner Version vor.

Code: Alles auswählen

  Procedure Deduplicate(List inout.stuff(), column.i, typ.i = #PB_String, dir.i = #PB_Sort_Ascending)
    SortStructuredList(inout(), dir, column * SizeOf(String), typ)
    
    Protected *compare.stuff = FirstElement(inout())
    If *compare
      While NextElement(inout())
        If *compare\s[column] = inout()\s[column]
          DeleteElement(inout())
        Else
          *compare = @inout()
        EndIf
      Wend
    EndIf
    
  EndProcedure
Das String in SizeOf(String) hab ich noch nie gesehen (eine Konstante ist es nicht, ein Schlüsselwort auch nicht) und wird auch nirgends deklariert.
Ich werde grade nicht schlau draus :shock: fahr ich in japbe drüber und drücke F1
poppt der Structur Anzeiger auf (den ich noch nie gesehen hab :lol: )

Dort steht

Code: Alles auswählen

Structure STRING
  s.s
EndStructure
Aber im Code oben wird die Structure stuff deklariert.

Code: Alles auswählen

  Structure stuff
    s.s[5]
  EndStructure
Woher weis der Compiler dann, welche Struktur bei SizeOf(String) vorkommt ? :shock:

EDIT2:

Ah ok weil es im Befehl

SortStructuredList(inout(), dir, column * SizeOf(String), typ)

vorkommt, wird automatisch die Structure verwendet die die inout() zugewiesen ist.

verstehe aber trotzdem noch nicht was das String bei SizeOf(String) ist.
https://www.geek.com/tech/a-commodore-6 ... s-1672510/
٩(̾●̮̮̃̾•̃̾)۶ __̴ı̴̴̡̡̡ ̡͌l̡̡̡ ̡͌l̡*̡̡ ̴̡ı̴̴̡ ̡̡͡|̲̲̲͡͡͡ ̲▫̲͡ ̲̲̲͡͡π̲̲͡͡ ̲̲͡▫̲̲͡͡ ̲|̡̡̡ ̡ ̴̡ı̴̡̡ ̡͌l̡̡̡̡.___٩(- ̮̮̃-̃)۶
Benutzeravatar
mhs
Beiträge: 224
Registriert: 11.01.2009 16:30
Wohnort: Graben
Kontaktdaten:

Re: [GELÖST] Structure Spalte ohne SpaltenNamen übergeben

Beitrag von mhs »

Das String ist eine von PB intern deklarierte Struktur, die eigentlich nur ein Feld \s hat. Die Struktur wird gerne für Referenzierungen verwendet, weil damit im Grund wiedergespiegelt wird, dass ein String eigentlich nur ein Zeiger auf einen Speicherbereich ist.
Michael Hack

Michael Hack Software :: Softwareentwicklung | Webentwicklung | IT-Dienstleistungen
www.michaelhacksoftware.de :: www.mh-s.de :: www.michael-hack.de
Antworten