Seite 1 von 1

ForEach bei Maps = verkehrte Reihenfolge?

Verfasst: 15.03.2024 22:44
von Delle
Mal eine Frage: wieso "sortiert" hier PB eigenmächtig, wenn man für den Key eine Zahl nimmt?

Bild

Habe mit Zahlen 100 - 125 fortlaufend (!) die Map gefüllt, Ausgabe mit ForEach ist dann nicht Start mit 100, sondern mit 120-125, danach beginnt er ab 100 hochzuzählen...

Gibt's eine Logik dahinter?

Re: ForEach bei Maps = verkehrte Reihenfolge?

Verfasst: 15.03.2024 23:01
von mk-soft
Es sind ja auch keine Zahlen, sondern Strings. Auch bei Zahlen werden diese nicht die gleiche Reihenfolge haben.
Maps sind immer unsortiert, da diese asl Hashtabelle abgelegt werden ...

Link: https://de.wikipedia.org/wiki/Hashtabelle

Re: ForEach bei Maps = verkehrte Reihenfolge?

Verfasst: 15.03.2024 23:02
von Kiffi
Auszug aus der PB-Hilfe hat geschrieben:Die Einfüge-Reihenfolge der Elemente wird beim Verwenden einer Map nicht gespeichert (anders als bei einer verknüpften Liste) und daher kann sie auch nicht sortiert werden.

Re: ForEach bei Maps = verkehrte Reihenfolge?

Verfasst: 16.03.2024 07:15
von DarkDragon
PB Maps sind als Hashtabellen implementiert. D.h. das läuft wie folgt:

Im Hintergrund hast du ein Array. Wird auf ein Element mit dem key X zugegriffen wird ein integer hashwert von X berechnet der möglichst kollisionsfrei ist und an der Stelle im Array wird nach dem Element gesucht. Die Reihenfolge wird nicht gewährleistet.

Zugriffszeit auf ein Element wäre damit konstant O(1). Bei einer Linked List wäre es O(n).

Re: ForEach bei Maps = verkehrte Reihenfolge?

Verfasst: 16.03.2024 10:57
von Delle
Mit einem führenden A funktioniert es:

Code: Alles auswählen

Country("A100")= ...
Country("A200")= ...
Country("A300")= ...
Aber gut vielleicht sollte ich das wirklich in LL's packen bzw. gleich in eine Datenbank, wenn dann auch noch weitere Elemente sortiert werden können sollen...

Re: ForEach bei Maps = verkehrte Reihenfolge?

Verfasst: 16.03.2024 15:35
von mk-soft
Du kannst auch eine Kombination von Listen und Maps verwenden.
Die Daten sind in der Liste und der Schnellzugriff über Maps mit Zeiger auf die Daten.
Hier muss aber immer die Liste und Maps sauber gepflegt werden, was aber gut geht.
Du kannst auch die Liste sortieren, da die Zeiger auf die Daten sich dabei nicht ändern.

Einzige Regel ist das der Name eindeutig sein muss. Dieses kann man aber über die Map abfragen ob es den Namen schon gibt

Code: Alles auswählen


Structure udtData
  Name.s
  Value.i
  Random.i
EndStructure

Global NewList myData.udtData()
Global NewMap *myNamedData.udtData()

Debug "Create data ..."

Define i, name.s

For i = 0 To 10000
  name = "A" + Str(i)
  *pData = AddElement(myData())
  myData()\Name = name
  myData()\Value = i
  myData()\Random = Random(5000, 1000)
  *myNamedData(Name) = *pData
Next

Debug "List Data ..."

ForEach myData()
  Debug myData()\Name + " Value = " + myData()\Value + " / Random = " + myData()\Random
  If myData()\Value > 10
    Break
  EndIf
Next

Debug "Get data over name ..."

name = "A6"
If FindMapElement(*myNamedData(), name)
  Debug myData()\Name + " Value = " + myData()\Value + " / Random = " + myData()\Random
Else
  Debug name + " nicht gefunden"
EndIf

name = "A9999"
If FindMapElement(*myNamedData(), name)
  Debug myData()\Name + " Value = " + myData()\Value + " / Random = " + myData()\Random
Else
  Debug name + " nicht gefunden"
EndIf

name = "A10001"
If FindMapElement(*myNamedData(), name)
  Debug myData()\Name + " Value = " + myData()\Value + " / Random = " + myData()\Random
Else
  Debug name + " nicht gefunden"
EndIf

Debug "Delete data over index ..."
i = 5001
SelectElement(myData(), i)
Debug "Delete " + myData()\Name
DeleteMapElement(*myNamedData(), myData()\Name)
DeleteElement(myData())

Debug "Delete data over name ..."
name = "A5005"
If FindMapElement(*myNamedData(), name)
  Debug "Delete " + name
  *pData = *myNamedData()
  ChangeCurrentElement(myData(), *pData)
  DeleteElement(myData())
  DeleteMapElement(*myNamedData())
EndIf

name = "A5005"
If FindMapElement(*myNamedData(), name)
  Debug name + "Value = " + *myNamedData()\Value
Else
  Debug name + " nicht gefunden"
EndIf

Debug "List Data ..."
SelectElement(myData(), 5000)
i = 1
Repeat
  Debug myData()\Name + " Value = " + myData()\Value + " / Random = " + myData()\Random
  i + 1
  If i > 10
    Break
  EndIf
Until Not NextElement(myData())

SortStructuredList(myData(), #PB_Sort_Ascending, OffsetOf(udtData\Random), #PB_Integer)

Debug "List Sorted Data ..."
SelectElement(myData(), 5000)
i = 1
Repeat
  Debug myData()\Name + " Value = " + myData()\Value + " / Random = " + myData()\Random
  i + 1
  If i > 10
    Break
  EndIf
Until Not NextElement(myData())

Debug "Get data over name ..."
name = "A5000"
If FindMapElement(*myNamedData(), name)
  Debug name + " Value = " + *myNamedData()\Value
Else
  Debug name + " nicht gefunden"
EndIf