dict

package module
v0.0.2 Latest Latest
Warning

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

Go to latest
Published: May 2, 2019 License: MIT Imports: 5 Imported by: 2

README

Dict

GoDoc Go Report Card Coverage Status Build Status

Python dictionary data type (dict) in Go

Package dict is a Go implementation of Python dict, which are hashable object maps. Dictionaries complement Go map and slice types to provide a simple interface to store and access key-value data with relatively fast performance at the cost of extra memory. This is done by using the features of both maps and slices.

Quick Start

Install using "go get":

go get github.com/srfrog/dict

Then import from your source:

import "github.com/srfrog/dict"

View example_test.go for an extended example of basic usage and features.

Features

  • Initialize a new dict with scalars, slices, maps, channels and other dictionaries.
  • Go types int, uint, float, string and fmt.Stringer are hashable for dict keys.
  • Go map keys are used for dict keys if they are hashable.
  • Dict items are sorted in their insertion order, unlike Go maps.
  • Go routine safe with minimal mutex locking (WIP)
  • Builtin JSON support for marshalling and unmarshalling
  • sql.Scanner support via optional sub-package (WIP)
  • Plenty of tests and examples to get you started quickly (WIP)

Documentation

The full code documentation is located at GoDoc:

http://godoc.org/github.com/srfrog/dict

The source code is thoroughly commented, have a look.

Usage

Minimal example showing basic usage:

package main

import (
   "github.com/srfrog/dict"
)

type Car struct {
   Model, BrandID string
}

func main() {
   // Map of car models, indexed by VIN.
   // Data source: NHTSA.gov
   vins := map[string]*Car{
      "2C3KA43R08H129584": &Car{
         Model:   "2008 CHRYSLER 300",
         BrandID: "ACB9976A-DB5F-4D57-B9A8-9F5C53D87C7C",
      },
      "1N6AD07U78C416152": &Car{
         Model:   "2008 NISSAN FRONTIER SE-V6 RWD",
         BrandID: "003096EE-C8FC-4C2F-ADEF-406F86C1F70B",
      },
      "WDDGF8AB8EA940372": &Car{
         Model:   "2014 Mercedes-Benz C300W4",
         BrandID: "57B7B707-4357-4306-9FD6-1EDCA43CF77B",
      },
   }

   // Create new dict and initialize with vins map.
   d := dict.New(vins)

   // Add a couple more VINs.
   d.Set("1N4AL2AP4BN404580", &Car{
      Model:   "2011 NISSAN ALTIMA 2.5 S CVT",
      BrandID: "003096EE-C8FC-4C2F-ADEF-406F86C1F70B",
   })
   d.Set("4T1BE46K48U762452", &Car{
      Model:   "2008 TOYOTA Camry",
      BrandID: "C5764FE4-F1E8-46BE-AFC6-A2FC90110387",
   })

   // Check current total
   fmt.Println("Total VIN Count:", d.Len())

   // Print VINs that have 3 or more recalls
   for item := range d.Items() {
      car, ok := item.Value.(*Car)
      if !ok {
         continue // Not a Car
      }
      if car.Recalls < 3 {
         continue // Not enough recalls
      }
      fmt.Println("---")
      fmt.Println("VIN:", item.Key)
   }
}

Documentation

Overview

Package dict is a Go implementation of Python dict, which are hashable object maps [1]. Dictionaries complement Go map and slice types to provide a simple interface to store and access key-value data with relatively fast performance at the cost of extra memory. This is done by using the features of both maps and slices.

A dict object is made of a key and value parts. A keys field is a slice that holds the order of values entered, which is the insertion order by default. Each key value contains the hash, index, or key ID, and the name of the key. The key value is used to find the value matching the key name in the values map, using the hash index. The values field in a dict object holds the values for a given key name, indexed by the hash index value.

The key names must be a supported hashable types. The hashable types are int, uint, float, string, and types that implement fmt.Stringer. The key ID is made using string values. The values stored in a dict can be any Go type, including other dict objects.

The func New() creates a new dict. It can take values to initialize the object. These can be slices, maps, channels and scalar values to create the dict. When using maps, the map keys must be hashable types that will be used as dict key IDs.

1- https://docs.python.org/3.7/library/stdtypes.html#dict

Example

Example shows a simple example of creating a new Dict and inserting values.

package main

import (
	"fmt"
	"time"

	"github.com/srfrog/dict"
)

type User struct {
	email  string
	name   string
	bday   time.Time
	social *dict.Dict
}

func main() {
	users := []*User{
		{
			email: "madison.horton90@example.com",
			name:  "Madison Horton",
			bday:  time.Date(1971, 7, 3, 0, 0, 0, 0, time.UTC),
		},
		{
			email: "amanda.wallace56@example.com",
			name:  "Amanda Wallace",
			bday:  time.Date(1978, 12, 6, 0, 0, 0, 0, time.UTC),
			social: dict.New(map[string]string{
				"twitter":   "@amandawall",
				"instagram": "@amanda_chill",
				"riot":      "xXxAmAnAcExXx",
			}),
		},
		{
			email: "morris.ryan98@example.com",
			name:  "Morris Ryan",
			bday:  time.Date(1984, 12, 5, 0, 0, 0, 0, time.UTC),
			social: dict.New(map[string]string{
				"linkedin": "ryan.p.morris",
			}),
		},
		{
			email: "riley.lawson20@example.com",
			name:  "Riley Lawson",
			bday:  time.Date(1984, 6, 7, 0, 0, 0, 0, time.UTC),
		},
		{
			email: "angel.perry56@example.com",
			name:  "Angel Perry",
			bday:  time.Date(1985, 8, 4, 0, 0, 0, 0, time.UTC),
		},
	}

	d := dict.New()

	// Add all users to dict. Use email as their map key.
	for _, user := range users {
		d.Set(user.email, user)
	}

	// Sanity: check that we in fact added users.
	if d.IsEmpty() {
		fmt.Println("The users dict is empty!")
		return
	}

	// Get user Amanda by email and print her info if found.
	// Get() returns an interface that will be nil if nothing is found, so we need
	// to make a type check to prevent type-assertion panic.
	user, ok := d.Get("amanda.wallace56@example.com").(*User)
	if !ok {
		fmt.Println("User was not found")
		return
	}

	// User was found, print the info.
	fmt.Println("Name:", user.name)
	fmt.Println("Birth year:", user.bday.Year())
	fmt.Println("Twitter:", user.social.Get("twitter"))

	// Amanda doesn't have WhatsApp listed, so this Get will return a nil value.
	fmt.Println("WhatsApp:", user.social.Get("whatsapp"))

	// We are done, clean up.
	if !d.Clear() {
		fmt.Println("Failed to clear")
	}

}
Output:

Name: Amanda Wallace
Birth year: 1978
Twitter: @amandawall
WhatsApp: <nil>

Index

Examples

Constants

View Source
const Version = "0.0.2"

Version is the version of this package.

Variables

This section is empty.

Functions

This section is empty.

Types

type Dict

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

Dict is a type that uses a hash mapping index, also known as a dictionary.

func New

func New(vargs ...interface{}) *Dict

New returns a new Dict object. vargs can be any Go basic type, slices, and maps. The keys in a map are used as keys in the dict. The map keys must be hashable.

func (*Dict) Clear

func (d *Dict) Clear() bool

Clear empties a Dict d. Returns true if the dict was actually cleared, otherwise false if nothing was done.

func (*Dict) Del

func (d *Dict) Del(key interface{}) bool

Del removes an item from dict by key name. Returns true if an item is found and removed, false otherwise.

func (*Dict) Get

func (d *Dict) Get(key interface{}, alt ...interface{}) interface{}

Get retrieves an item from dict by key. If alt value is passed, it will be used as default value if no item is found. Returns a value matching key in dict, otherwise nil or alt if given.

func (*Dict) GetKeyID

func (d *Dict) GetKeyID(key interface{}) (uint64, bool)

GetKeyID retrieves the ID of an item in dict, if found. Returns the item ID and true, or 0 and false if not found.

func (*Dict) IsEmpty

func (d *Dict) IsEmpty() bool

IsEmpty returns true if the dict is empty, false otherwise.

func (*Dict) Items

func (d *Dict) Items() <-chan Item

Items returns a channel of key-value items, or nil if the dict is empty.

func (*Dict) Key

func (d *Dict) Key(key interface{}) bool

Key returns true if key is in dict d, false otherwise.

func (*Dict) Keys

func (d *Dict) Keys() []string

Keys returns a string slice of all dict keys, or nil if dict is empty.

func (*Dict) Len

func (d *Dict) Len() int

Len returns the size of a Dict.

func (*Dict) MarshalJSON added in v0.0.2

func (d *Dict) MarshalJSON() ([]byte, error)

MarshalJSON implements the json.MarshalJSON interface. The JSON representation of dict is just a JSON object.

func (*Dict) Pop

func (d *Dict) Pop(key interface{}, alt ...interface{}) interface{}

Pop gets the value of a key and removes the item from the dict. If the item is not found it returns alt. Otherwise it will return the value or nil.

func (*Dict) PopItem

func (d *Dict) PopItem() *Item

PopItem removes the most recent item added to the dict and returns it. If the dict is empty, returns nil.

func (*Dict) Set

func (d *Dict) Set(key, value interface{}) *Dict

Set inserts a new item into the dict. If a value matching the key already exists, its value is replaced, otherwise a new item is added.

func (*Dict) UnmarshalJSON added in v0.0.2

func (d *Dict) UnmarshalJSON(p []byte) error

UnmarshalJSON implements the json.UnmarshalJSON interface. The JSON representation of dict is just a JSON object.

func (*Dict) Update

func (d *Dict) Update(vargs ...interface{}) bool

Update adds to d the key-value items from iterables, scalars and other dicts. Also replacing any existing values that match the keys. This func is used by New() when initializing a dict with values. Returns true if any changes were made.

Example

ExampleDict_Update shows a dict that is updated with another using Update().

package main

import (
	"fmt"

	"github.com/srfrog/dict"
)

type Car struct {
	Model, BrandID string
	Recalls        int
	History        *dict.Dict
}

func main() {
	// Map of cars, indexed by VIN.
	// Data source: NHTSA.gov
	vins := map[string]*Car{
		"2C3KA43R08H129584": &Car{
			Model:   "2008 CHRYSLER 300",
			Recalls: 3,
			BrandID: "ACB9976A-DB5F-4D57-B9A8-9F5C53D87C7C",
		},
		"1N6AD07U78C416152": &Car{
			Model:   "2008 NISSAN FRONTIER SE-V6 RWD",
			Recalls: 0,
			BrandID: "003096EE-C8FC-4C2F-ADEF-406F86C1F70B",
		},
		"WDDGF8AB8EA940372": &Car{
			Model:   "2014 Mercedes-Benz C300W4",
			Recalls: 2,
			BrandID: "57B7B707-4357-4306-9FD6-1EDCA43CF77B",
		},
	}

	// Create new dict and initialize with vins map.
	d := dict.New(vins)

	// Add a couple more VINs.
	d.Set("1N4AL2AP4BN404580", &Car{
		Model:   "2011 NISSAN ALTIMA 2.5 S CVT",
		Recalls: 0,
		BrandID: "003096EE-C8FC-4C2F-ADEF-406F86C1F70B",
	})
	d.Set("4T1BE46K48U762452", &Car{
		Model:   "2008 TOYOTA Camry",
		Recalls: 3,
		BrandID: "C5764FE4-F1E8-46BE-AFC6-A2FC90110387",
		History: dict.New().
			Set("2008/10/21", "Vehicle sold").
			Set("2010/08/03", "Car was washed without soap"),
	})

	// Check total
	fmt.Println("Total VIN Count:", d.Len())

	// We store brands in their own dict, maybe sourced from another DB.
	brandIDs := dict.New().
		Set("ACB9976A-DB5F-4D57-B9A8-9F5C53D87C7C", "Chrysler").
		Set("003096EE-C8FC-4C2F-ADEF-406F86C1F70B", "Nissan").
		Set("57B7B707-4357-4306-9FD6-1EDCA43CF77B", "Mercedes-Benz").
		Set("C5764FE4-F1E8-46BE-AFC6-A2FC90110387", "Toyota")

	// // Keep VINs and BrandIDs in the same dict.
	d.Update(brandIDs)

	// Print VINs that have 3 or more recalls
	for item := range d.Items() {
		car, ok := item.Value.(*Car)
		if !ok {
			continue // Not a Car
		}
		if car.Recalls < 3 {
			continue // Not enough recalls
		}
		fmt.Println("---")
		fmt.Println("VIN:", item.Key)
		fmt.Println("Brand:", d.Get(car.BrandID))
		fmt.Println("Model:", car.Model)
		fmt.Println("Recalls:", car.Recalls)
		fmt.Println("Logs:", car.History.Keys())
	}

}
Output:

Total VIN Count: 5
---
VIN: 2C3KA43R08H129584
Brand: Chrysler
Model: 2008 CHRYSLER 300
Recalls: 3
Logs: []
---
VIN: 4T1BE46K48U762452
Brand: Toyota
Model: 2008 TOYOTA Camry
Recalls: 3
Logs: [2008/10/21 2010/08/03]

func (*Dict) Values

func (d *Dict) Values() []interface{}

Values returns a slice of all dict values, or nil if dict is empty.

func (*Dict) Version

func (d *Dict) Version() int

Version returns the version of the dictionary. The version is increased after every change to dict items. Returns version, which is zero (0) initially.

type Item

type Item struct {
	Key   interface{}
	Value interface{}
}

Item is a key-value pair. Key is the key name value. Value is the stored value in dict.

type Key

type Key struct {
	ID   uint64
	Name string
}

Key represents a key value. Keys are used to order the items in a dict. ID is a 64 bit hash value representation of Name. Name is the user-friendly and sortable name.

func MakeKey

func MakeKey(value interface{}) *Key

MakeKey generates a Key object by hashing the provided value. The value type must be float, int, uint, string, or that implements Stringer. Returns a new Key object if successful, otherwise returns nil.

type Stringer

type Stringer interface {
	String() string
}

Stringer is just like fmt.Stringer without loading that package.

Jump to

Keyboard shortcuts

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