@ -2,16 +2,16 @@
// Use of this source code is governed by a BSD-style
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// license that can be found in the LICENSE file.
// Package treebidimap implements a bidirectional map backed by a red-black tree.
// Package treebidimap implements a bidirectional map backed by two red-black tree.
//
// This structure guarantees that the map will be in both ascending key and value order.
// This structure guarantees that the map will be in both ascending key and value order.
// The goal with this structure is to avoid duplication of elements, which can be significant if contained elements are large.
//
// Other than key and value ordering, the goal with this structure is to avoid duplication of elements, which can be significant if contained elements are large.
//
//
// A bidirectional map, or hash bag, is an associative data structure in which the (key,value) pairs form a one-to-one correspondence.
// A bidirectional map, or hash bag, is an associative data structure in which the (key,value) pairs form a one-to-one correspondence.
// Thus the binary relation is functional in each direction: value can also act as a key to key.
// Thus the binary relation is functional in each direction: value can also act as a key to key.
// A pair (a,b) thus provides a unique coupling between 'a' and 'b' so that 'b' can be found when 'a' is used as a key and 'a' can be found when 'b' is used as a key.
// A pair (a,b) thus provides a unique coupling between 'a' and 'b' so that 'b' can be found when 'a' is used as a key and 'a' can be found when 'b' is used as a key.
//
//
// Elements are unordered in the map.
//
// Structure is not thread safe.
// Structure is not thread safe.
//
//
// Reference: https://en.wikipedia.org/wiki/Bidirectional_map
// Reference: https://en.wikipedia.org/wiki/Bidirectional_map
@ -20,53 +20,79 @@ package treebidimap
import (
import (
"fmt"
"fmt"
"github.com/emirpasic/gods/maps"
"github.com/emirpasic/gods/maps"
"github.com/emirpasic/gods/maps/hashmap"
"github.com/emirpasic/gods/trees/redblacktree"
"github.com/emirpasic/gods/utils"
)
)
func assertMapImplementation ( ) {
func assertMapImplementation ( ) {
var _ maps . BidiMap = ( * Map ) ( nil )
var _ maps . BidiMap = ( * Map ) ( nil )
}
}
// Map holds the elements in two hashmap s.
// Map holds the elements in two red-black tree s.
type Map struct {
type Map struct {
forwardMap hashmap . Map
forwardMap redblacktree . Tree
inverseMap hashmap . Map
inverseMap redblacktree . Tree
}
type data struct {
key interface { }
value interface { }
}
// NewWith instantiates a bidirectional map.
func NewWith ( keyComparator utils . Comparator , valueComparator utils . Comparator ) * Map {
return & Map {
forwardMap : * redblacktree . NewWith ( keyComparator ) ,
inverseMap : * redblacktree . NewWith ( valueComparator ) ,
}
}
// NewWithIntComparators instantiates a bidirectional map with the IntComparator for key and value, i.e. keys and values are of type int.
func NewWithIntComparators ( ) * Map {
return NewWith ( utils . IntComparator , utils . IntComparator )
}
}
// New instantiates a bidirectional map.
// New WithStringComparators instantiates a bidirectional map with the StringComparator for key and value, i.e. keys and values are of type string .
func New ( ) * Map {
func New WithStringComparators ( ) * Map {
return & Map { * hashmap . New ( ) , * hashmap . New ( ) }
return NewWith ( utils . StringComparator , utils . StringComparator )
}
}
// Put inserts element into the map.
// Put inserts element into the map.
func ( m * Map ) Put ( key interface { } , value interface { } ) {
func ( m * Map ) Put ( key interface { } , value interface { } ) {
if valueByKey , ok := m . forwardMap . Get ( key ) ; ok {
if d , ok := m . forwardMap . Get ( key ) ; ok {
m . inverseMap . Remove ( valueByKey )
m . inverseMap . Remove ( d. ( * data ) . value)
}
}
if keyByValue , ok := m . inverseMap . Get ( value ) ; ok {
if d , ok := m . inverseMap . Get ( value ) ; ok {
m . forwardMap . Remove ( keyByValue )
m . forwardMap . Remove ( d. ( * data ) . key)
}
}
m . forwardMap . Put ( key , value )
d := & data { key : key , value : value }
m . inverseMap . Put ( value , key )
m . forwardMap . Put ( key , d )
m . inverseMap . Put ( value , d )
}
}
// Get searches the element in the map by key and returns its value or nil if key is not found in map.
// Get searches the element in the map by key and returns its value or nil if key is not found in map.
// Second return parameter is true if key was found, otherwise false.
// Second return parameter is true if key was found, otherwise false.
func ( m * Map ) Get ( key interface { } ) ( value interface { } , found bool ) {
func ( m * Map ) Get ( key interface { } ) ( value interface { } , found bool ) {
return m . forwardMap . Get ( key )
if d , ok := m . forwardMap . Get ( key ) ; ok {
return d . ( * data ) . value , true
}
return nil , false
}
}
// GetKey searches the element in the map by value and returns its key or nil if value is not found in map.
// GetKey searches the element in the map by value and returns its key or nil if value is not found in map.
// Second return parameter is true if value was found, otherwise false.
// Second return parameter is true if value was found, otherwise false.
func ( m * Map ) GetKey ( value interface { } ) ( key interface { } , found bool ) {
func ( m * Map ) GetKey ( value interface { } ) ( key interface { } , found bool ) {
return m . inverseMap . Get ( value )
if d , ok := m . inverseMap . Get ( value ) ; ok {
return d . ( * data ) . key , true
}
return nil , false
}
}
// Remove removes the element from the map by key.
// Remove removes the element from the map by key.
func ( m * Map ) Remove ( key interface { } ) {
func ( m * Map ) Remove ( key interface { } ) {
if value , found := m . forwardMap . Get ( key ) ; found {
if d , found := m . forwardMap . Get ( key ) ; found {
m . forwardMap . Remove ( key )
m . forwardMap . Remove ( key )
m . inverseMap . Remove ( value)
m . inverseMap . Remove ( d. ( * data ) . value)
}
}
}
}
@ -80,12 +106,12 @@ func (m *Map) Size() int {
return m . forwardMap . Size ( )
return m . forwardMap . Size ( )
}
}
// Keys returns all keys ( random order).
// Keys returns all keys ( ordered ).
func ( m * Map ) Keys ( ) [ ] interface { } {
func ( m * Map ) Keys ( ) [ ] interface { } {
return m . forwardMap . Keys ( )
return m . forwardMap . Keys ( )
}
}
// Values returns all values ( random order).
// Values returns all values ( ordered ).
func ( m * Map ) Values ( ) [ ] interface { } {
func ( m * Map ) Values ( ) [ ] interface { } {
return m . inverseMap . Keys ( )
return m . inverseMap . Keys ( )
}
}
@ -98,7 +124,7 @@ func (m *Map) Clear() {
// String returns a string representation of container
// String returns a string representation of container
func ( m * Map ) String ( ) string {
func ( m * Map ) String ( ) string {
str := " Hash Map\n"
str := " TreeBidi Map\n"
str += fmt . Sprintf ( "%v" , m . forwardMap )
str += fmt . Sprintf ( "%v" , m . forwardMap )
return str
return str
}
}