jsonmap

package module
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 25, 2023 License: MIT Imports: 6 Imported by: 5

README

Ordered map

go test workflow

Simple ordered map for Go, with JSON restrictions. The main purpose is to keep same order of keys after parsing JSON and generating it again, so Unmarshal followed by Marshal generates exactly the same JSON structure

Keys are strings, Values are any JSON values (number, string, boolean, null, array, map/object)

Storage is O(n), operations are O(1), except for optional operations in slow.go file

When Unmarshalling, any nested map from JSON is created as ordered, including maps in nested arrays

Alternative implementation is in simplemap, it has simple structure, O(1) Keys, but O(n) Delete operation. Check the difference by running go test -v -bench=. -benchmem

Inspired by wk8/go-ordered-map and iancoleman/orderedmap

Usage

package main

import (
	"encoding/json"
	"fmt"

	"github.com/metalim/jsonmap"
	// or simpler alternative, but with O(n) Delete()
	// jsonmap "github.com/metalim/jsonmap/simplemap"
)

const input = `{"an":"article","empty":null,"sub":{"s":1,"e":2,"x":3,"y":4},"bool":false,"array":[1,2,3]}`

func main() {
	m := jsonmap.New()

	// unmarshal, keeping order
	err := json.Unmarshal([]byte(input), &m)
	if err != nil {
		panic(err)
	}

	// get values
	val, ok := m.Get("an")
	fmt.Println("an: ", val, ok) // article true
	val, ok = m.Get("non-existant")
	fmt.Println("non-existant", val, ok) // <nil> false

	// marshal, keeping order
	output, err := json.Marshal(&m)
	if err != nil {
		panic(err)
	}

	if string(output) == input {
		fmt.Println("output == input")
	}

	// iterate
	fmt.Println("forward order:")
	for el := m.First(); el != nil; el = el.Next() {
		fmt.Printf("\t%s: %v\n", el.Key(), el.Value())
	}
	fmt.Println()

	fmt.Println("backwards order:")
	for el := m.Last(); el != nil; el = el.Prev() {
		fmt.Printf("\t%s: %v\n", el.Key(), el.Value())
	}
	fmt.Println()

	fmt.Println(`forward from key "sub":`)
	for el := m.GetElement("sub"); el != nil; el = el.Next() {
		fmt.Printf("\t%s: %v\n", el.Key(), el.Value())
	}
	fmt.Println()

	// print map
	fmt.Println(m) // map[an:article empty:<nil> sub:map[s:1 e:2 x:3 y:4] bool:false array:[1 2 3]]

	// set new values, keeping order of existing keys
	m.Set("an", "bar")
	m.Set("truth", true)
	fmt.Println(m) // map[an:bar empty:<nil> sub:map[s:1 e:2 x:3 y:4] bool:false array:[1 2 3] truth:true]

	// delete key "sub"
	m.Delete("sub")
	fmt.Println(m) // map[an:bar empty:<nil> bool:false array:[1 2 3] truth:true]

	// update value for key "an", and move it to the end
	m.Push("an", "end")
	fmt.Println(m) // map[empty:<nil> bool:false array:[1 2 3] truth:true an:end]

	data, err := json.Marshal(&m)
	if err != nil {
		panic(err)
	}
	fmt.Println(string(data)) // {"empty":null,"bool":false,"array":[1,2,3],"truth":true,"an":"end"}
}

Alternatives

Let me know of other alternatives, I'll add them here

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func GetAs added in v0.3.0

func GetAs[T any](m *Map, key string) (value T, ok bool)

Types

type Element added in v0.2.0

type Element struct {
	// contains filtered or unexported fields
}

func (*Element) Key added in v0.2.0

func (e *Element) Key() Key

func (*Element) Next added in v0.2.0

func (e *Element) Next() *Element

func (*Element) Prev added in v0.2.0

func (e *Element) Prev() *Element

func (*Element) Value added in v0.2.0

func (e *Element) Value() Value

type Key

type Key = string

type Map

type Map struct {
	// contains filtered or unexported fields
}

func New

func New() *Map

func (*Map) Clear added in v0.2.0

func (m *Map) Clear()

func (*Map) Delete

func (m *Map) Delete(key string)

func (*Map) Elements added in v0.2.0

func (m *Map) Elements() []*Element

O(n)

func (*Map) First added in v0.2.0

func (m *Map) First() *Element

func (*Map) ForEach added in v0.2.0

func (m *Map) ForEach(f func(key Key, value Value))

optional, as it can't be stopped

func (*Map) Get

func (m *Map) Get(key string) (value any, ok bool)

func (*Map) GetElement added in v0.2.0

func (m *Map) GetElement(key string) *Element

func (*Map) KeyIndex added in v0.2.0

func (m *Map) KeyIndex(key string) int

O(n)

func (*Map) Keys

func (m *Map) Keys() []Key

O(n)

func (*Map) Last added in v0.2.0

func (m *Map) Last() *Element

func (*Map) Len

func (m *Map) Len() int

func (*Map) MarshalJSON

func (m *Map) MarshalJSON() ([]byte, error)

func (*Map) Merge added in v0.2.0

func (m *Map) Merge(other *Map)

func (*Map) Push

func (m *Map) Push(key Key, value Value)

func (*Map) PushFront added in v0.2.0

func (m *Map) PushFront(key Key, value Value)

func (*Map) Set

func (m *Map) Set(key Key, value Value)

func (*Map) SetFront added in v0.2.0

func (m *Map) SetFront(key Key, value Value)

func (*Map) SortKeys added in v0.2.0

func (m *Map) SortKeys(less func(a, b Key) bool)

O(n log n)

func (*Map) String added in v0.2.0

func (m *Map) String() string

func (*Map) UnmarshalJSON

func (m *Map) UnmarshalJSON(data []byte) error

func (*Map) Values added in v0.2.0

func (m *Map) Values() []Value

O(n)

type Value

type Value = any

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL