Datový typ map!

1. Úvod

Struktura typu map! reprezentuje asociativní array dvojic key/value. Poskytuje rychlý přístup pro čtení s interním použitím hashtable. Na rozdíl od datového typu hash! nepatří map! do skupiny series!, tudíž nezná koncept pozic (nemá interní iterátor). Koncepčně leží typ map! mezi datovými typy hash! a object!. Uživatelsky připomíná slovník.

2. Literálová skladba

#(<key> <value>...)

<key>   : hashovaný klíč, akceptované typy jsou: scalar!, all-word!, any-string!
<value> : hodnota typu any-type!

Příklad:

#(a: 1 b: 2)
== #(
    a: 1
    b: 2   )

3. Creation syntax

make map! <spec>

<spec> : blok párů `key/value` nebo jedno celé číslo.

Je-li argumentem spec celé číslo, vytvoří se prázdný objekt map! s přednastaveným počtem slotů (obvykle za účelem dynamického zaplnění mapy).

make map! 10
== #()
Note
  • tělo mapy nebo blok specifikací musí mít sudý počet elementů

  • hodnoty nejsou redukovány, takže pro některé speciení hodnoty (jako je např. logic!) je potřebné použít strukturální (construction) formu deklarace.

Příklad:

make map! [a 1 'b 2 "c" 3]
== #(
    a: 1
    b: 2
	"c" 3
)

Je-li klíč typu any-word (zde a, e), je v mapě kvůli lepší přehlednosti konvertován na typ set-word. Nicméně lze pro klíč z praktických důvodů (jednodušší zápis, zejména u cest) použít prostý tvar slova místo typu set-word!.

Podobně reflektor keys-of (popsaný v sekci Reflexe níže) vrací words místo set-words, jelikož to zjednodušuje další zpracování - zejména srovnávací (matching) operace jsou snadnější se slovy než se set-words.

Note
  • Entita map je podobně jako hash! a block! implicitně "case-preserving" a "case-insensitive" při vyhledávání slova.

  • Všechny klíče jsou při vytváření mapy "deep copied".

  • Hodnoty typu series! nejsou při vytváření mapy kopírovány. Volba je ponechána na uživateli, což optimializuje zdroje při obecném použití.

Jiný způsob vytvoření nové mapy je s použitím akce copy u mapy existující.

4. Vyjímání hodnot

S použitím cesty:

<map>/<key>
get '<map>/<key>

<map>: slovo, odkazující na objekt typu map!
<key>: slovo, označující klíč

S použitím funkce select:

select <map> <'key>

Všechny tyto přístupy jsou case-insensitive. Case-sensitive vyhledání zařídíme upřesněním /case.

get/case '<map>/<key>
select/case <map> <key>

Pokus o přístup k nedefinovanému klíči způsobí:

  • vytvoření chybového hlášení, je-li použita skladba cesty

  • návrat hodnoty none, je-li použita funkce select.

Příklady:

m: #(Ab: 2 aB: 5 ab: 10)
m/ab
== 2
select m 'aB
== 2
get/case 'm/aB
== 5
select/case m 'ab
== 10
select m 'x
== none

5. Změna klíčů a hodnot

S použitím cesty:

<map>/<key>: <value>
set '<map>/<key> <value>

<map>   : word referring to a map! value
<key>   : word key to select a value in the map
<value> : any value

Úprava dvojice key/value:

put <map> <key> <value>

<map> : map value
<key> : any valid key value to select a value in the map

Hromadné změny:

extend <map> <spec>

<map>  : map value
<spec> : block of name/value pairs (one or more pairs)

Všechny tyto zápisy jsou case-insensitive. Pro case-sensitive vyhledání je potřebné použít upřesnění /case, kde je to možné:

set/case '<map>/<key> <value>
put/case <map> <key> <value>
extend/case <map> <spec>

Nativní funkce extend může přijmout více klíčů najednou, takže je vhodná pro hromadné změny.

m: make map! 5
== #()

extend m [a: 5 b: none!]
== #(
    a: 5             ; type integer!
    b: none!         ; type word!
)
Note
  • zadání klíče, který dosud v mapě neexistuje, způsobí jeho vytvoření.

  • přidání existujícího klíče změní jeho hodnotu, přičemž se implicitně provádí case-insensitive porovnávání.

Příklady:

m: #(Ab: 2 aB: 5 ab: 10)
m/ab: 3
== 3

m
== #(
    Ab: 3
    aB: 5
    ab: 10
)

put m 'aB "hello"
m
== #(
    Ab: "hello"
    aB: 5
    ab: 10
)

set/case 'm/aB 0
m
== #(
    Ab: "hello"
    aB: 0
    ab: 10
)
set/case 'm/ab 192.168.0.1
m
== #(
    Ab: "hello"
    aB: 0
    ab: 192.168.0.1
)

m: #(%cities.red 10)
extend m [%cities.red 99 %countries.red 7 %states.red 27]
m
== #(
    %cities.red 99
    %countries.red 7
    %states.red 27
)

6. Mazání klíčů

Dvojici key/value jednoduše z mapy vymažeme příkazem remove/key. Smažou se všechny klíče, počínaje zadaným a vrátí se jeho hodnota. Vyhledávání je vždy case-sensitive.

Příklad:

m: #(a: 1 b 2 "c" 3 d: 99)
== #(
    a: 1
    b: 2
    "c" 3
    d: 99
)

remove/key m 'b
== #(a: 1 "c" 3 d: 99)

Je rovněž možné smazat všechny klíče najednou akcí clear:

clear #(a 1 b 2 c 3)
== #()

7. Reflexe

Pro práci s mapou (slovníkem) se s výhodou použijí další pomocné funkce:

  • find ověří přítomnost klíče v mapě a vrátí true, byl-li nalezen, v opačném případě vrátí none. Pro case-sensitive srovnávání použijte upřesnění /case.

    find #(a 123 b 456) 'b
    == b
    find #(a 123 A 456) 'A
    == a
    find/case #(a 123 A 456) 'A
    == A
  • length? vrací počet dvojic key/value v mapě.

    length? #(a 123 b 456)
    == 2
  • keys-of vrací seznam klíčů v mapě formou bloku (set-words are converted to words).

    keys-of #(a: 123 b: 456)
    == [a b]
  • values-of vrací seznam hodnot v mapě.

    values-of #(a: 123 b: 456)
    == [123 456]
  • body-of vrací všechny dvojice key/value v mapě.

    body-of #(a: 123 b: 456)
    == [a: 123 b: 456]

8. Iterace

  • Použití keys-of s foreach

    >> foreach k keys-of #(a: 123 b: 456) [print k]
    a
    b
  • Použití values-of s foreach

    >> foreach v values-of #(a: 123 b: 456) [print v]
    123
    456
  • Bez keys-of nebo values-of musí být zadán blok se dvěmi slovy

    >> foreach [k v] #(a: 123 b: 456) [print [k v]]
    a 123
    b 456

results matching ""

    No results matching ""