Page 1 of 1

ChangeCurrentMapElement()

Posted: Tue Mar 14, 2017 12:17 am
by Josh
As there is no ChangeCurrentMapElement() I don't see a native way to get the MapKey from a pointer to the mapelement.

Actually I'm using this workaround, but a native way would be better:

Code: Select all

  Define *GE.String
  Define *FR.String
  Define *UK.String

  NewMap Country.s()

  *GE = AddMapElement (Country(), "GE") : Country() = "Germany"
  *FR = AddMapElement (Country(), "FR") : Country() = "France"
  *UK = AddMapElement (Country(), "UK") : Country() = "United Kingdom"

  Debug *GE\s
  Debug *FR\s
  Debug *UK\s

  *GE - SizeOf (Integer)
  *FR - SizeOf (Integer)
  *UK - SizeOf (Integer)

  Debug *GE\s
  Debug *FR\s
  Debug *UK\s
  

Re: ChangeCurrentMapElement()

Posted: Tue Mar 14, 2017 1:31 am
by Thunder93
Edit: Realized you was asking for slightly different thing. :wink:

Re: ChangeCurrentMapElement()

Posted: Tue Mar 14, 2017 2:35 am
by normeus
@Josh
I am replying because I enjoy using MAPS since my PERL days:

you should be able to use FindMapElement() and if it finds the key then the map is set to that key:

Code: Select all

  NewMap Country.s()

  Country("GE") = "Germany"
  Country("FR") = "France"
  Country("UK") = "United Kingdom"
   
  If FindMapElement(Country(), "FR")
    Debug country()
    Debug  MapKey(country())
  EndIf
  
Again I have fun using maps this way.
Thank you.
Norm.

Re: ChangeCurrentMapElement()

Posted: Tue Mar 14, 2017 3:01 am
by nco2k
@normeus
with ChangeCurrentMapElement(), you could directly jump to the element, by using the pointer. with FindMapElement(), you have to "search" for the element first. i know maps are pretty fast, but nothing beats a direct pointer.

c ya,
nco2k

Re: ChangeCurrentMapElement()

Posted: Tue Mar 14, 2017 3:04 am
by Thunder93
+1 for Josh request. :wink:

Re: ChangeCurrentMapElement()

Posted: Tue Mar 14, 2017 4:37 am
by Demivec
nco2k wrote:@normeus
with ChangeCurrentMapElement(), you could directly jump to the element, by using the pointer. with FindMapElement(), you have to "search" for the element first. i know maps are pretty fast, but nothing beats a direct pointer.
In the case of a map, being able to jump directly to an element is only useful for deleting it.

Using its pointer you can already read and change the element without accessing the map. Maps also are not sorted so 'jumping' directly to an element via a pointer is not going to provide valuable access to the previous or the following elements.

Respectfully, have I overlooked some other mysterious and useful aspect of being able to 'jump' directly to an element in a map?

Re: ChangeCurrentMapElement()

Posted: Tue Mar 14, 2017 5:48 am
by Josh
Demivec wrote:In the case of a map, being able to jump directly to an element is only useful for deleting it.
.......
Respectfully, have I overlooked some other mysterious and useful aspect of being able to 'jump' directly to an element in a map?
Yes, you have. Exactly this one, why I opened this topic and described it in my first post.

I showed a workaround, but there should be a native way like:

Code: Select all

ChangeCurrentMapElement (Country(), *FR)
Debug MapKey (Country())

Re: ChangeCurrentMapElement()

Posted: Tue Mar 14, 2017 7:37 am
by Demivec
Josh wrote:
Demivec wrote:Respectfully, have I overlooked some other mysterious and useful aspect of being able to 'jump' directly to an element in a map?
Yes, you have. Exactly this one, I have described in my first post
Haha, your absolutely right. :) I tested your sample code but overlooked your exact reason for posting it, my apologies.
Josh wrote:I showed a workaround, but there should be a native way like:

Code: Select all

ChangeCurrentMapElement (Country(), *FR)
Debug MapKey (Country())
Just for fun, here's another workaround using your method as a macro:

Code: Select all

Macro MapkeyFromPointer(pointer)
  PeekS(PeekI(pointer - SizeOf(Integer)))
EndMacro
Here's your demonstration code with a small change:

Code: Select all

Macro MapkeyFromPointer(pointer)
  PeekS(PeekI(pointer - SizeOf(Integer)))
EndMacro

Define *GE.String
Define *FR.String
Define *UK.String

NewMap Country.s()

*GE = AddMapElement (Country(), "GE") : Country() = "Germany"
*FR = AddMapElement (Country(), "FR") : Country() = "France"
*UK = AddMapElement (Country(), "UK") : Country() = "United Kingdom"

Debug *GE\s
Debug *FR\s
Debug *UK\s

Debug MapkeyFromPointer(*GE)
Debug MapkeyFromPointer(*FR)
Debug MapkeyFromPointer(*UK)

Re: ChangeCurrentMapElement()

Posted: Tue Mar 14, 2017 7:44 am
by Josh
It works, but it is a workaround. A native way is always the better way and future-proof.

Re: ChangeCurrentMapElement()

Posted: Mon Sep 04, 2017 6:18 pm
by Little John
Oops ... I've missed the request for this feature, which I would like to have available in PureBasic, too. :-)

Not exactly rarely, I store data in both a map and a corresponding list.
The map is good for quick direct access, and the list is good for well-arranged enumeration (e.g. after sorting, or after individual arrangement of the elements by me).

Up to now, I've used a solution according to an approach by Stargate (German forum). This is demonstrated in the first part of the code below.
However, the disadvantage of this approach is, that the strings used as keys (which can be long) are stored twice: as map keys, and also in the "key$" field of the structure.

The second part of the code below shows a different approach, that uses pointers to map keys: the keys are only stored once. If ChangeCurrentMapElement() (or something equivalent) would be implemented in PureBasic, I think it would be a rather efficient approach for dealing with this kind of stuff.

So +10 for this request from me. :-)

Code: Select all

EnableExplicit

Structure myMember
   key$
   value.i
EndStructure

NewList myList.myMember()
NewMap *myMap.myMember()

Macro MyNewElement (_key_, _value_)
   *myMap(_key_) = AddElement(myList())
   myList()\key$ = _key_
   myList()\value = _value_
EndMacro

MyNewElement("alpha", 1)
MyNewElement("beta",  2)
MyNewElement("gamma", 3)
MyNewElement("delta", 4)

Debug "-- Quick direct access, using the map:"
Debug "beta = " + *myMap("beta")\value
Debug ""

Debug "-- Well-arranged enumeration, using the list:"
ForEach myList()
   Debug myList()\key$ + " = " + myList()\value
Next

Debug ""
Debug "--------------------------------------------------"
Debug ""

Structure yourMember
   value.i
EndStructure

NewMap yourMap.yourMember()
NewList *yourList.String()

Macro YourNewElement (_key_, _value_)
   yourMap(_key_)\value = _value_
   AddElement(*yourList())
   *yourList() = @yourMap() - SizeOf(Integer)
EndMacro

YourNewElement("alpha", 1)
YourNewElement("beta",  2)
YourNewElement("gamma", 3)
YourNewElement("delta", 4)

Debug "-- Quick direct access, using the map:"
Debug "beta = " + yourMap("beta")\value
Debug ""

Debug "-- Well-arranged enumeration, using the list and the map:"
ForEach *yourList()
   ; * In a future PB version, this could be done officially and more
   ;   efficiently e.g. with a built-in command ChangeCurrentMapElement(): *
   Debug *yourList()\s + " = " + yourMap(*yourList()\s)\value
Next

Re: ChangeCurrentMapElement()

Posted: Wed Sep 06, 2017 9:14 am
by Andy
I would also like a ChangeCurrentMapElement () function... :)

I've already wondered that there is such a function for lists, but not for maps. I've also asked myself, what it should bring me, when the functions of the maps give me pointers, but there are no functions that use them. Sure, I can work directly with pointers - but for hobby programmers like me, using pointers is hard to understand.

The reason I would like this is the same as already described by others: additional ways to manage the elements of the map.