Skip to content

Enhanced Golang Map: support one unique key and multi search indices for each value

License

Notifications You must be signed in to change notification settings

starwander/emap

Repository files navigation

Enhanced Golang Map

Build Status codecov Go Report Card GoDoc License

EMap implements an enhanced map in Golang. The main enhancement of emap over original golang map is the support of searching index.

  • Values in the emap can have one or more indices which can be used to search or delete.
  • Key in the emap must be unique as same as the key in the golang map.
  • Index in the emap is an N to M relation which mean a value can have multi indices and multi values can have one same index.

##Several Choices #####Generic EMap

  • The generic emap has no restrict for the type of its key, value and index.
  • The generic emap has a read-write locker inside so it is concurrent safe.

#####Expirable EMap

  • The expirable emap has no restrict for the type of its key, value and index.
  • The expirable emap has a read-write locker inside so it is concurrent safe.
  • The expirable emap will check all the values in the emap with the period of input interval(milliseconds). If a value is expired, it will be deleted automatically.

#####Strict EMap

  • The types of key, value and index used in the strict emap are determined during initialization by the sample inputs.
  • All methods of the strict emap must use the same type of the sample inputs otherwise an error will be returned.
  • The strict emap has a read-write locker inside so it is concurrent safe.

#####Unlock EMap

  • The unlock emap has no restrict for the type of its key, value and index.
  • The unlock emap has no locker or mutex inside, so it is not concurrent safe.
  • It is only suitable for those models like Event Loop to achieve better performance.

##Requirements #####Download this package

go get github.com/starwander/emap

#####Implements ExpirableValue interface of this package for all values if ExpirableEmap is chosen

// ExpirableValue is the interface which must be implemented by all the value in the expirable EMap.
type ExpirableValue interface {
	// IsExpired returns if the value is expired.
	// If true, the value will be deleted automatically.
	IsExpired() bool
}

Basic Operations

  • Insert: pushes a new value into emap with input key and indices.
  • FetchByKey: gets the value in the emap by input key.
  • FetchByIndex: gets the all values in the emap by input index.
  • DeleteByKey: deletes the value in the emap by input key.
  • DeleteByIndex: deletes all the values in the emap by input index.
  • AddIndex: add the input index to the value in the emap of the input key.
  • RemoveIndex: remove the input index from the value in the emap of the input key.
  • KeyNum: returns the total key number in the emap.
  • KeyNumOfIndex: returns the total key number of the input index in the emap.
  • IndexNum: returns the total index number in the emap.
  • IndexNumOfKey: returns the total index number of the input key in the emap.
  • HasKey: returns if the input key exists in the emap.
  • HasIndex: returns if the input index exists in the emap.

Higher-order Operations

  • Transform:
  • Transform is a higher-order operation which apply the input callback function to each key-value pair in the emap.
  • Any error returned by the callback function will interrupt the transforming and the error will be returned.
  • If transform successfully, a new golang map is created with each key-value pair returned by the input callback function.
  • Foreach:
  • Foreach is a higher-order operation which apply the input callback function to each key-value pair in the emap.
  • Since the callback function has no return, the foreach procedure will never be interrupted.
  • A typical usage of Foreach is apply a closure.

Example

package main

import (
	"fmt"
	"github.com/starwander/emap"
	"time"
)

type employee struct {
	name       string
	gender     string
	department string
	retired    bool
	//hobby      []string
}

type emplyeeByDept struct {
	name       string
	department string
}

func (e *employee) IsExpired() bool {
	return e.retired
}

func main() {
	emap := emap.NewExpirableEMap(1000)

	emap.Insert("Tom", &employee{"Tom", "Male", "R&D", false}, "R&D", "swimming", "hiking")
	emap.Insert("Jerry", &employee{"Jerry", "Male", "Sales", false}, "Sales", "football", "hiking")
	emap.Insert("Carol", &employee{"Carol", "Female", "HR", false}, "HR", "movie")
	emap.Insert("Jessie", &employee{"Jessie", "Female", "Sales", false}, "Sales", "hiking", "cycling")

	fmt.Println(emap.KeyNum())                //4
	fmt.Println(emap.IndexNum())              //8
	fmt.Println(emap.IndexNumOfKey("Tom"))    //3
	fmt.Println(emap.KeyNumOfIndex("hiking")) //3

	fmt.Println(emap.FetchByKey("Carol")) // &{Carol Female HR false} <nil>
	allSales, _ := emap.FetchByIndex("Sales")
	for _, each := range allSales {
		//&{Jerry Male Sales false}
		//&{Jessie Female Sales false}
		fmt.Println(each.(*employee))
	}

	emap.RemoveIndex("Jerry", "hiking")
	allHiking, _ := emap.FetchByIndex("hiking")
	for _, each := range allHiking {
		//&{Tom Male R&D false}
		//&{Jessie Female Sales false}
		fmt.Println(each.(*employee))
	}
	emap.AddIndex("Jessie", "movie")
	allMovie, _ := emap.FetchByIndex("movie")
	for _, each := range allMovie {
		//&{Carol Female HR false}
		//&{Jessie Female Sales false}
		fmt.Println(each.(*employee))
	}

	emap.DeleteByKey("Jerry")
	fmt.Println(emap.KeyNum()) //3

	nameAndDept, _ := emap.Transform(func(n interface{}, e interface{}) (interface{}, error) {
		return &emplyeeByDept{n.(string), e.(*employee).department}, nil
	})
	for _, each := range nameAndDept {
		//&{Jessie Sales}
		//&{Tom R&D}
		//&{Carol HR}
		fmt.Println(each.(*emplyeeByDept))
	}

	var totalMaleNum, totalFemalNum int
	emap.Foreach(func(n interface{}, e interface{}) {
		if e.(*employee).gender == "Male" {
			totalMaleNum++
		} else {
			totalFemalNum++
		}
	})
	fmt.Println("Total male number:", totalMaleNum, "Total female number:", totalFemalNum) //Total male number: 1 Total female number: 2

	carol, _ := emap.FetchByKey("Carol")
	carol.(*employee).retired = true
	time.Sleep(1100 * time.Millisecond)
	fmt.Println(emap.FetchByKey("Carol")) //<nil> key not exist
}

Reference

GoDoc

LICENSE

EMap source code is licensed under the Apache Licence, Version 2.0.

About

Enhanced Golang Map: support one unique key and multi search indices for each value

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages