Merge pull request #91 from emirpasic/development

LinkedHashMap
pull/94/head v1.11.0
Emir Pasic 6 years ago committed by GitHub
commit 7aedbffbed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -21,6 +21,7 @@ Implementation of various data structures and algorithms in Go.
- [Maps](#maps)
- [HashMap](#hashmap)
- [TreeMap](#treemap)
- [LinkedHashMap](#linkedhashmap)
- [HashBidiMap](#hashbidimap)
- [TreeBidiMap](#treebidimap)
- [Trees](#trees)
@ -63,23 +64,24 @@ Containers are either ordered or unordered. All ordered containers provide [stat
| **Data** | **Structure** | **Ordered** | **[Iterator](#iterator)** | **[Enumerable](#enumerable)** | **Referenced by** |
| :--- | :--- | :---: | :---: | :---: | :---: |
| **[Lists](#lists)** |
| [Lists](#lists) |
| | [ArrayList](#arraylist) | yes | yes* | yes | index |
| | [SinglyLinkedList](#singlylinkedlist) | yes | yes | yes | index |
| | [DoublyLinkedList](#doublylinkedlist) | yes | yes* | yes | index |
| **[Sets](#sets)** |
| [Sets](#sets) |
| | [HashSet](#hashset) | no | no | no | index |
| | [TreeSet](#treeset) | yes | yes* | yes | index |
| | [LinkedHashSet](#linkedhashset) | yes | yes* | yes | index |
| **[Stacks](#stacks)** |
| [Stacks](#stacks) |
| | [LinkedListStack](#linkedliststack) | yes | yes | no | index |
| | [ArrayStack](#arraystack) | yes | yes* | no | index |
| **[Maps](#maps)** |
| [Maps](#maps) |
| | [HashMap](#hashmap) | no | no | no | key |
| | [TreeMap](#treemap) | yes | yes* | yes | key |
| | [LinkedHashMap](#linkedhashmap) | yes | yes* | yes | key |
| | [HashBidiMap](#hashbidimap) | no | no | no | key* |
| **[Trees](#trees)** |
| | [TreeBidiMap](#treebidimap) | yes | yes* | yes | key* |
| [Trees](#trees) |
| | [RedBlackTree](#redblacktree) | yes | yes* | no | key |
| | [AVLTree](#avltree) | yes | yes* | no | key |
| | [BTree](#btree) | yes | yes* | no | key |
@ -487,6 +489,34 @@ func main() {
}
```
#### LinkedHashMap
A [map](#maps) that preserves insertion-order. It is backed by a hash table to store values and [doubly-linked list](doublylinkedlist) to store ordering.
Implements [Map](#maps), [IteratorWithKey](#iteratorwithkey), [EnumerableWithKey](#enumerablewithkey), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces.
```go
package main
import "github.com/emirpasic/gods/maps/linkedhashmap"
func main() {
m := linkedhashmap.New() // empty (keys are of type int)
m.Put(2, "b") // 2->b
m.Put(1, "x") // 2->b, 1->x (insertion-order)
m.Put(1, "a") // 2->b, 1->a (insertion-order)
_, _ = m.Get(2) // b, true
_, _ = m.Get(3) // nil, false
_ = m.Values() // []interface {}{"b", "a"} (insertion-order)
_ = m.Keys() // []interface {}{2, 1} (insertion-order)
m.Remove(1) // 2->b
m.Clear() // empty
m.Empty() // true
m.Size() // 0
}
```
#### HashBidiMap
A [map](#maps) based on two hashmaps. Keys are unordered.

@ -0,0 +1,23 @@
// Copyright (c) 2015, Emir Pasic. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import "github.com/emirpasic/gods/maps/linkedhashmap"
// LinkedHashMapExample to demonstrate basic usage of LinkedHashMapExample
func main() {
m := linkedhashmap.New() // empty (keys are of type int)
m.Put(2, "b") // 2->b
m.Put(1, "x") // 2->b, 1->x (insertion-order)
m.Put(1, "a") // 2->b, 1->a (insertion-order)
_, _ = m.Get(2) // b, true
_, _ = m.Get(3) // nil, false
_ = m.Values() // []interface {}{"b", "a"} (insertion-order)
_ = m.Keys() // []interface {}{2, 1} (insertion-order)
m.Remove(1) // 2->b
m.Clear() // empty
m.Empty() // true
m.Size() // 0
}

@ -14,12 +14,12 @@ func assertSerializationImplementation() {
var _ containers.JSONDeserializer = (*Map)(nil)
}
// ToJSON outputs the JSON representation of list's elements.
// ToJSON outputs the JSON representation of the map.
func (m *Map) ToJSON() ([]byte, error) {
return m.forwardMap.ToJSON()
}
// FromJSON populates list's elements from the input JSON representation.
// FromJSON populates the map from the input JSON representation.
func (m *Map) FromJSON(data []byte) error {
elements := make(map[string]interface{})
err := json.Unmarshal(data, &elements)

@ -15,7 +15,7 @@ func assertSerializationImplementation() {
var _ containers.JSONDeserializer = (*Map)(nil)
}
// ToJSON outputs the JSON representation of list's elements.
// ToJSON outputs the JSON representation of the map.
func (m *Map) ToJSON() ([]byte, error) {
elements := make(map[string]interface{})
for key, value := range m.m {
@ -24,7 +24,7 @@ func (m *Map) ToJSON() ([]byte, error) {
return json.Marshal(&elements)
}
// FromJSON populates list's elements from the input JSON representation.
// FromJSON populates the map from the input JSON representation.
func (m *Map) FromJSON(data []byte) error {
elements := make(map[string]interface{})
err := json.Unmarshal(data, &elements)

@ -0,0 +1,80 @@
// Copyright (c) 2015, Emir Pasic. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package linkedhashmap
import "github.com/emirpasic/gods/containers"
func assertEnumerableImplementation() {
var _ containers.EnumerableWithKey = (*Map)(nil)
}
// Each calls the given function once for each element, passing that element's key and value.
func (m *Map) Each(f func(key interface{}, value interface{})) {
iterator := m.Iterator()
for iterator.Next() {
f(iterator.Key(), iterator.Value())
}
}
// Map invokes the given function once for each element and returns a container
// containing the values returned by the given function as key/value pairs.
func (m *Map) Map(f func(key1 interface{}, value1 interface{}) (interface{}, interface{})) *Map {
newMap := New()
iterator := m.Iterator()
for iterator.Next() {
key2, value2 := f(iterator.Key(), iterator.Value())
newMap.Put(key2, value2)
}
return newMap
}
// Select returns a new container containing all elements for which the given function returns a true value.
func (m *Map) Select(f func(key interface{}, value interface{}) bool) *Map {
newMap := New()
iterator := m.Iterator()
for iterator.Next() {
if f(iterator.Key(), iterator.Value()) {
newMap.Put(iterator.Key(), iterator.Value())
}
}
return newMap
}
// Any passes each element of the container to the given function and
// returns true if the function ever returns true for any element.
func (m *Map) Any(f func(key interface{}, value interface{}) bool) bool {
iterator := m.Iterator()
for iterator.Next() {
if f(iterator.Key(), iterator.Value()) {
return true
}
}
return false
}
// All passes each element of the container to the given function and
// returns true if the function returns true for all elements.
func (m *Map) All(f func(key interface{}, value interface{}) bool) bool {
iterator := m.Iterator()
for iterator.Next() {
if !f(iterator.Key(), iterator.Value()) {
return false
}
}
return true
}
// Find passes each element of the container to the given function and returns
// the first (key,value) for which the function is true or nil,nil otherwise if no element
// matches the criteria.
func (m *Map) Find(f func(key interface{}, value interface{}) bool) (interface{}, interface{}) {
iterator := m.Iterator()
for iterator.Next() {
if f(iterator.Key(), iterator.Value()) {
return iterator.Key(), iterator.Value()
}
}
return nil, nil
}

@ -0,0 +1,81 @@
// Copyright (c) 2015, Emir Pasic. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package linkedhashmap
import (
"github.com/emirpasic/gods/containers"
"github.com/emirpasic/gods/lists/doublylinkedlist"
)
func assertIteratorImplementation() {
var _ containers.ReverseIteratorWithKey = (*Iterator)(nil)
}
// Iterator holding the iterator's state
type Iterator struct {
iterator doublylinkedlist.Iterator
table map[interface{}]interface{}
}
// Iterator returns a stateful iterator whose elements are key/value pairs.
func (m *Map) Iterator() Iterator {
return Iterator{
iterator: m.ordering.Iterator(),
table: m.table}
}
// Next moves the iterator to the next element and returns true if there was a next element in the container.
// If Next() returns true, then next element's key and value can be retrieved by Key() and Value().
// If Next() was called for the first time, then it will point the iterator to the first element if it exists.
// Modifies the state of the iterator.
func (iterator *Iterator) Next() bool {
return iterator.iterator.Next()
}
// Prev moves the iterator to the previous element and returns true if there was a previous element in the container.
// If Prev() returns true, then previous element's key and value can be retrieved by Key() and Value().
// Modifies the state of the iterator.
func (iterator *Iterator) Prev() bool {
return iterator.iterator.Prev()
}
// Value returns the current element's value.
// Does not modify the state of the iterator.
func (iterator *Iterator) Value() interface{} {
key := iterator.iterator.Value()
return iterator.table[key]
}
// Key returns the current element's key.
// Does not modify the state of the iterator.
func (iterator *Iterator) Key() interface{} {
return iterator.iterator.Value()
}
// Begin resets the iterator to its initial state (one-before-first)
// Call Next() to fetch the first element if any.
func (iterator *Iterator) Begin() {
iterator.iterator.Begin()
}
// End moves the iterator past the last element (one-past-the-end).
// Call Prev() to fetch the last element if any.
func (iterator *Iterator) End() {
iterator.iterator.End()
}
// First moves the iterator to the first element and returns true if there was a first element in the container.
// If First() returns true, then first element's key and value can be retrieved by Key() and Value().
// Modifies the state of the iterator
func (iterator *Iterator) First() bool {
return iterator.iterator.First()
}
// Last moves the iterator to the last element and returns true if there was a last element in the container.
// If Last() returns true, then last element's key and value can be retrieved by Key() and Value().
// Modifies the state of the iterator.
func (iterator *Iterator) Last() bool {
return iterator.iterator.Last()
}

@ -0,0 +1,109 @@
// Copyright (c) 2015, Emir Pasic. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package linkedhashmap is a map that preserves insertion-order.
//
// It is backed by a hash table to store values and doubly-linked list to store ordering.
//
// Structure is not thread safe.
//
// Reference: http://en.wikipedia.org/wiki/Associative_array
package linkedhashmap
import (
"fmt"
"github.com/emirpasic/gods/lists/doublylinkedlist"
"github.com/emirpasic/gods/maps"
"strings"
)
func assertMapImplementation() {
var _ maps.Map = (*Map)(nil)
}
// Map holds the elements in a red-black tree
type Map struct {
table map[interface{}]interface{}
ordering *doublylinkedlist.List
}
// New instantiates a linked-hash-map.
func New() *Map {
return &Map{
table: make(map[interface{}]interface{}),
ordering: doublylinkedlist.New(),
}
}
// Put inserts key-value pair into the map.
// Key should adhere to the comparator's type assertion, otherwise method panics.
func (m *Map) Put(key interface{}, value interface{}) {
if _, contains := m.table[key]; !contains {
m.ordering.Append(key)
}
m.table[key] = value
}
// Get searches the element in the map by key and returns its value or nil if key is not found in tree.
// Second return parameter is true if key was found, otherwise false.
// Key should adhere to the comparator's type assertion, otherwise method panics.
func (m *Map) Get(key interface{}) (value interface{}, found bool) {
value = m.table[key]
found = value != nil
return
}
// Remove removes the element from the map by key.
// Key should adhere to the comparator's type assertion, otherwise method panics.
func (m *Map) Remove(key interface{}) {
if _, contains := m.table[key]; contains {
delete(m.table, key)
index := m.ordering.IndexOf(key)
m.ordering.Remove(index)
}
}
// Empty returns true if map does not contain any elements
func (m *Map) Empty() bool {
return m.Size() == 0
}
// Size returns number of elements in the map.
func (m *Map) Size() int {
return m.ordering.Size()
}
// Keys returns all keys in-order
func (m *Map) Keys() []interface{} {
return m.ordering.Values()
}
// Values returns all values in-order based on the key.
func (m *Map) Values() []interface{} {
values := make([]interface{}, m.Size())
count := 0
it := m.Iterator()
for it.Next() {
values[count] = it.Value()
count++
}
return values
}
// Clear removes all elements from the map.
func (m *Map) Clear() {
m.table = make(map[interface{}]interface{})
m.ordering.Clear()
}
// String returns a string representation of container
func (m *Map) String() string {
str := "LinkedHashMap\nmap["
it := m.Iterator()
for it.Next() {
str += fmt.Sprintf("%v:%v ", it.Key(), it.Value())
}
return strings.TrimRight(str, " ") + "]"
}

@ -0,0 +1,643 @@
// Copyright (c) 2015, Emir Pasic. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package linkedhashmap
import (
"fmt"
"testing"
)
func TestMapPut(t *testing.T) {
m := New()
m.Put(5, "e")
m.Put(6, "f")
m.Put(7, "g")
m.Put(3, "c")
m.Put(4, "d")
m.Put(1, "x")
m.Put(2, "b")
m.Put(1, "a") //overwrite
if actualValue := m.Size(); actualValue != 7 {
t.Errorf("Got %v expected %v", actualValue, 7)
}
if actualValue, expectedValue := m.Keys(), []interface{}{5, 6, 7, 3, 4, 1, 2}; !sameElements(actualValue, expectedValue) {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
if actualValue, expectedValue := m.Values(), []interface{}{"e", "f", "g", "c", "d", "a", "b"}; !sameElements(actualValue, expectedValue) {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
// key,expectedValue,expectedFound
tests1 := [][]interface{}{
{1, "a", true},
{2, "b", true},
{3, "c", true},
{4, "d", true},
{5, "e", true},
{6, "f", true},
{7, "g", true},
{8, nil, false},
}
for _, test := range tests1 {
// retrievals
actualValue, actualFound := m.Get(test[0])
if actualValue != test[1] || actualFound != test[2] {
t.Errorf("Got %v expected %v", actualValue, test[1])
}
}
}
func TestMapRemove(t *testing.T) {
m := New()
m.Put(5, "e")
m.Put(6, "f")
m.Put(7, "g")
m.Put(3, "c")
m.Put(4, "d")
m.Put(1, "x")
m.Put(2, "b")
m.Put(1, "a") //overwrite
m.Remove(5)
m.Remove(6)
m.Remove(7)
m.Remove(8)
m.Remove(5)
if actualValue, expectedValue := m.Keys(), []interface{}{3, 4, 1, 2}; !sameElements(actualValue, expectedValue) {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
if actualValue, expectedValue := m.Values(), []interface{}{"c", "d", "a", "b"}; !sameElements(actualValue, expectedValue) {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
if actualValue := m.Size(); actualValue != 4 {
t.Errorf("Got %v expected %v", actualValue, 4)
}
tests2 := [][]interface{}{
{1, "a", true},
{2, "b", true},
{3, "c", true},
{4, "d", true},
{5, nil, false},
{6, nil, false},
{7, nil, false},
{8, nil, false},
}
for _, test := range tests2 {
actualValue, actualFound := m.Get(test[0])
if actualValue != test[1] || actualFound != test[2] {
t.Errorf("Got %v expected %v", actualValue, test[1])
}
}
m.Remove(1)
m.Remove(4)
m.Remove(2)
m.Remove(3)
m.Remove(2)
m.Remove(2)
if actualValue, expectedValue := fmt.Sprintf("%s", m.Keys()), "[]"; actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
if actualValue, expectedValue := fmt.Sprintf("%s", m.Values()), "[]"; actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
if actualValue := m.Size(); actualValue != 0 {
t.Errorf("Got %v expected %v", actualValue, 0)
}
if actualValue := m.Empty(); actualValue != true {
t.Errorf("Got %v expected %v", actualValue, true)
}
}
func sameElements(a []interface{}, b []interface{}) bool {
// If one is nil, the other must also be nil.
if (a == nil) != (b == nil) {
return false
}
if len(a) != len(b) {
return false
}
for i := range a {
if a[i] != b[i] {
return false
}
}
return true
}
func TestMapEach(t *testing.T) {
m := New()
m.Put("c", 1)
m.Put("a", 2)
m.Put("b", 3)
count := 0
m.Each(func(key interface{}, value interface{}) {
count++
if actualValue, expectedValue := count, value; actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
switch value {
case 1:
if actualValue, expectedValue := key, "c"; actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
case 2:
if actualValue, expectedValue := key, "a"; actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
case 3:
if actualValue, expectedValue := key, "b"; actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
default:
t.Errorf("Too many")
}
})
}
func TestMapMap(t *testing.T) {
m := New()
m.Put("c", 3)
m.Put("a", 1)
m.Put("b", 2)
mappedMap := m.Map(func(key1 interface{}, value1 interface{}) (key2 interface{}, value2 interface{}) {
return key1, value1.(int) * value1.(int)
})
if actualValue, _ := mappedMap.Get("c"); actualValue != 9 {
t.Errorf("Got %v expected %v", actualValue, "mapped: c")
}
if actualValue, _ := mappedMap.Get("a"); actualValue != 1 {
t.Errorf("Got %v expected %v", actualValue, "mapped: a")
}
if actualValue, _ := mappedMap.Get("b"); actualValue != 4 {
t.Errorf("Got %v expected %v", actualValue, "mapped: b")
}
if mappedMap.Size() != 3 {
t.Errorf("Got %v expected %v", mappedMap.Size(), 3)
}
}
func TestMapSelect(t *testing.T) {
m := New()
m.Put("c", 3)
m.Put("b", 1)
m.Put("a", 2)
selectedMap := m.Select(func(key interface{}, value interface{}) bool {
return key.(string) >= "a" && key.(string) <= "b"
})
if actualValue, _ := selectedMap.Get("b"); actualValue != 1 {
t.Errorf("Got %v expected %v", actualValue, "value: a")
}
if actualValue, _ := selectedMap.Get("a"); actualValue != 2 {
t.Errorf("Got %v expected %v", actualValue, "value: b")
}
if selectedMap.Size() != 2 {
t.Errorf("Got %v expected %v", selectedMap.Size(), 2)
}
}
func TestMapAny(t *testing.T) {
m := New()
m.Put("c", 3)
m.Put("a", 1)
m.Put("b", 2)
any := m.Any(func(key interface{}, value interface{}) bool {
return value.(int) == 3
})
if any != true {
t.Errorf("Got %v expected %v", any, true)
}
any = m.Any(func(key interface{}, value interface{}) bool {
return value.(int) == 4
})
if any != false {
t.Errorf("Got %v expected %v", any, false)
}
}
func TestMapAll(t *testing.T) {
m := New()
m.Put("c", 3)
m.Put("a", 1)
m.Put("b", 2)
all := m.All(func(key interface{}, value interface{}) bool {
return key.(string) >= "a" && key.(string) <= "c"
})
if all != true {
t.Errorf("Got %v expected %v", all, true)
}
all = m.All(func(key interface{}, value interface{}) bool {
return key.(string) >= "a" && key.(string) <= "b"
})
if all != false {
t.Errorf("Got %v expected %v", all, false)
}
}
func TestMapFind(t *testing.T) {
m := New()
m.Put("c", 3)
m.Put("a", 1)
m.Put("b", 2)
foundKey, foundValue := m.Find(func(key interface{}, value interface{}) bool {
return key.(string) == "c"
})
if foundKey != "c" || foundValue != 3 {
t.Errorf("Got %v -> %v expected %v -> %v", foundKey, foundValue, "c", 3)
}
foundKey, foundValue = m.Find(func(key interface{}, value interface{}) bool {
return key.(string) == "x"
})
if foundKey != nil || foundValue != nil {
t.Errorf("Got %v at %v expected %v at %v", foundValue, foundKey, nil, nil)
}
}
func TestMapChaining(t *testing.T) {
m := New()
m.Put("c", 3)
m.Put("a", 1)
m.Put("b", 2)
chainedMap := m.Select(func(key interface{}, value interface{}) bool {
return value.(int) > 1
}).Map(func(key interface{}, value interface{}) (interface{}, interface{}) {
return key.(string) + key.(string), value.(int) * value.(int)
})
if actualValue := chainedMap.Size(); actualValue != 2 {
t.Errorf("Got %v expected %v", actualValue, 2)
}
if actualValue, found := chainedMap.Get("aa"); actualValue != nil || found {
t.Errorf("Got %v expected %v", actualValue, nil)
}
if actualValue, found := chainedMap.Get("bb"); actualValue != 4 || !found {
t.Errorf("Got %v expected %v", actualValue, 4)
}
if actualValue, found := chainedMap.Get("cc"); actualValue != 9 || !found {
t.Errorf("Got %v expected %v", actualValue, 9)
}
}
func TestMapIteratorNextOnEmpty(t *testing.T) {
m := New()
it := m.Iterator()
it = m.Iterator()
for it.Next() {
t.Errorf("Shouldn't iterate on empty map")
}
}
func TestMapIteratorPrevOnEmpty(t *testing.T) {
m := New()
it := m.Iterator()
it = m.Iterator()
for it.Prev() {
t.Errorf("Shouldn't iterate on empty map")
}
}
func TestMapIteratorNext(t *testing.T) {
m := New()
m.Put("c", 1)
m.Put("a", 2)
m.Put("b", 3)
it := m.Iterator()
count := 0
for it.Next() {
count++
key := it.Key()
value := it.Value()
switch key {
case "c":
if actualValue, expectedValue := value, 1; actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
case "a":
if actualValue, expectedValue := value, 2; actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
case "b":
if actualValue, expectedValue := value, 3; actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
default:
t.Errorf("Too many")
}
if actualValue, expectedValue := value, count; actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
}
if actualValue, expectedValue := count, 3; actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
}
func TestMapIteratorPrev(t *testing.T) {
m := New()
m.Put("c", 1)
m.Put("a", 2)
m.Put("b", 3)
it := m.Iterator()
for it.Next() {
}
countDown := m.Size()
for it.Prev() {
key := it.Key()
value := it.Value()
switch key {
case "c":
if actualValue, expectedValue := value, 1; actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
case "a":
if actualValue, expectedValue := value, 2; actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
case "b":
if actualValue, expectedValue := value, 3; actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
default:
t.Errorf("Too many")
}
if actualValue, expectedValue := value, countDown; actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
countDown--
}
if actualValue, expectedValue := countDown, 0; actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
}
func TestMapIteratorBegin(t *testing.T) {
m := New()
it := m.Iterator()
it.Begin()
m.Put(3, "c")
m.Put(1, "a")
m.Put(2, "b")
for it.Next() {
}
it.Begin()
it.Next()
if key, value := it.Key(), it.Value(); key != 3 || value != "c" {
t.Errorf("Got %v,%v expected %v,%v", key, value, 3, "c")
}
}
func TestMapTreeIteratorEnd(t *testing.T) {
m := New()
it := m.Iterator()
m.Put(3, "c")
m.Put(1, "a")
m.Put(2, "b")
it.End()
it.Prev()
if key, value := it.Key(), it.Value(); key != 2 || value != "b" {
t.Errorf("Got %v,%v expected %v,%v", key, value, 2, "b")
}
}
func TestMapIteratorFirst(t *testing.T) {
m := New()
m.Put(3, "c")
m.Put(1, "a")
m.Put(2, "b")
it := m.Iterator()
if actualValue, expectedValue := it.First(), true; actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
if key, value := it.Key(), it.Value(); key != 3 || value != "c" {
t.Errorf("Got %v,%v expected %v,%v", key, value, 3, "c")
}
}
func TestMapIteratorLast(t *testing.T) {
m := New()
m.Put(3, "c")
m.Put(1, "a")
m.Put(2, "b")
it := m.Iterator()
if actualValue, expectedValue := it.Last(), true; actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
if key, value := it.Key(), it.Value(); key != 2 || value != "b" {
t.Errorf("Got %v,%v expected %v,%v", key, value, 2, "b")
}
}
func TestMapSerialization(t *testing.T) {
for i := 0; i < 10; i++ {
original := New()
original.Put("d", "4")
original.Put("e", "5")
original.Put("c", "3")
original.Put("b", "2")
original.Put("a", "1")
assertSerialization(original, "A", t)
serialized, err := original.ToJSON()
if err != nil {
t.Errorf("Got error %v", err)
}
assertSerialization(original, "B", t)
deserialized := New()
err = deserialized.FromJSON(serialized)
if err != nil {
t.Errorf("Got error %v", err)
}
assertSerialization(deserialized, "C", t)
}
}
//noinspection GoBoolExpressions
func assertSerialization(m *Map, txt string, t *testing.T) {
if actualValue := m.Keys(); false ||
actualValue[0].(string) != "d" ||
actualValue[1].(string) != "e" ||
actualValue[2].(string) != "c" ||
actualValue[3].(string) != "b" ||
actualValue[4].(string) != "a" {
t.Errorf("[%s] Got %v expected %v", txt, actualValue, "[d,e,c,b,a]")
}
if actualValue := m.Values(); false ||
actualValue[0].(string) != "4" ||
actualValue[1].(string) != "5" ||
actualValue[2].(string) != "3" ||
actualValue[3].(string) != "2" ||
actualValue[4].(string) != "1" {
t.Errorf("[%s] Got %v expected %v", txt, actualValue, "[4,5,3,2,1]")
}
if actualValue, expectedValue := m.Size(), 5; actualValue != expectedValue {
t.Errorf("[%s] Got %v expected %v", txt, actualValue, expectedValue)
}
}
func benchmarkGet(b *testing.B, m *Map, size int) {
for i := 0; i < b.N; i++ {
for n := 0; n < size; n++ {
m.Get(n)
}
}
}
func benchmarkPut(b *testing.B, m *Map, size int) {
for i := 0; i < b.N; i++ {
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
}
}
}
func benchmarkRemove(b *testing.B, m *Map, size int) {
for i := 0; i < b.N; i++ {
for n := 0; n < size; n++ {
m.Remove(n)
}
}
}
func BenchmarkTreeMapGet100(b *testing.B) {
b.StopTimer()
size := 100
m := New()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
}
b.StartTimer()
benchmarkGet(b, m, size)
}
func BenchmarkTreeMapGet1000(b *testing.B) {
b.StopTimer()
size := 1000
m := New()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
}
b.StartTimer()
benchmarkGet(b, m, size)
}
func BenchmarkTreeMapGet10000(b *testing.B) {
b.StopTimer()
size := 10000
m := New()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
}
b.StartTimer()
benchmarkGet(b, m, size)
}
func BenchmarkTreeMapGet100000(b *testing.B) {
b.StopTimer()
size := 100000
m := New()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
}
b.StartTimer()
benchmarkGet(b, m, size)
}
func BenchmarkTreeMapPut100(b *testing.B) {
b.StopTimer()
size := 100
m := New()
b.StartTimer()
benchmarkPut(b, m, size)
}
func BenchmarkTreeMapPut1000(b *testing.B) {
b.StopTimer()
size := 1000
m := New()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
}
b.StartTimer()
benchmarkPut(b, m, size)
}
func BenchmarkTreeMapPut10000(b *testing.B) {
b.StopTimer()
size := 10000
m := New()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
}
b.StartTimer()
benchmarkPut(b, m, size)
}
func BenchmarkTreeMapPut100000(b *testing.B) {
b.StopTimer()
size := 100000
m := New()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
}
b.StartTimer()
benchmarkPut(b, m, size)
}
func BenchmarkTreeMapRemove100(b *testing.B) {
b.StopTimer()
size := 100
m := New()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
}
b.StartTimer()
benchmarkRemove(b, m, size)
}
func BenchmarkTreeMapRemove1000(b *testing.B) {
b.StopTimer()
size := 1000
m := New()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
}
b.StartTimer()
benchmarkRemove(b, m, size)
}
func BenchmarkTreeMapRemove10000(b *testing.B) {
b.StopTimer()
size := 10000
m := New()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
}
b.StartTimer()
benchmarkRemove(b, m, size)
}
func BenchmarkTreeMapRemove100000(b *testing.B) {
b.StopTimer()
size := 100000
m := New()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
}
b.StartTimer()
benchmarkRemove(b, m, size)
}

@ -0,0 +1,103 @@
// Copyright (c) 2015, Emir Pasic. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package linkedhashmap
import (
"bytes"
"encoding/json"
"github.com/emirpasic/gods/containers"
"github.com/emirpasic/gods/utils"
)
func assertSerializationImplementation() {
var _ containers.JSONSerializer = (*Map)(nil)
var _ containers.JSONDeserializer = (*Map)(nil)
}
// ToJSON outputs the JSON representation of map.
func (m *Map) ToJSON() ([]byte, error) {
var b []byte
buf := bytes.NewBuffer(b)
buf.WriteRune('{')
it := m.Iterator()
lastIndex := m.Size() - 1
index := 0
for it.Next() {
km, err := json.Marshal(it.Key())
if err != nil {
return nil, err
}
buf.Write(km)
buf.WriteRune(':')
vm, err := json.Marshal(it.Value())
if err != nil {
return nil, err
}
buf.Write(vm)
if index != lastIndex {
buf.WriteRune(',')
}
index++
}
buf.WriteRune('}')
return buf.Bytes(), nil
}
// FromJSON populates map from the input JSON representation.
//func (m *Map) FromJSON(data []byte) error {
// elements := make(map[string]interface{})
// err := json.Unmarshal(data, &elements)
// if err == nil {
// m.Clear()
// for key, value := range elements {
// m.Put(key, value)
// }
// }
// return err
//}
// FromJSON populates map from the input JSON representation.
func (m *Map) FromJSON(data []byte) error {
elements := make(map[string]interface{})
err := json.Unmarshal(data, &elements)
if err != nil {
return err
}
index := make(map[string]int)
var keys []interface{}
for key := range elements {
keys = append(keys, key)
esc, _ := json.Marshal(key)
index[key] = bytes.Index(data, esc)
}
byIndex := func(a, b interface{}) int {
key1 := a.(string)
key2 := b.(string)
index1 := index[key1]
index2 := index[key2]
return index1 - index2
}
utils.Sort(keys, byIndex)
m.Clear()
for _, key := range keys {
m.Put(key, elements[key.(string)])
}
return nil
}

@ -15,7 +15,7 @@ func assertSerializationImplementation() {
var _ containers.JSONDeserializer = (*Map)(nil)
}
// ToJSON outputs the JSON representation of list's elements.
// ToJSON outputs the JSON representation of the map.
func (m *Map) ToJSON() ([]byte, error) {
elements := make(map[string]interface{})
it := m.Iterator()
@ -25,7 +25,7 @@ func (m *Map) ToJSON() ([]byte, error) {
return json.Marshal(&elements)
}
// FromJSON populates list's elements from the input JSON representation.
// FromJSON populates the map from the input JSON representation.
func (m *Map) FromJSON(data []byte) error {
elements := make(map[string]interface{})
err := json.Unmarshal(data, &elements)

@ -474,34 +474,52 @@ func TestMapIteratorLast(t *testing.T) {
}
func TestMapSerialization(t *testing.T) {
m := NewWithStringComparators()
m.Put("a", "1")
m.Put("b", "2")
m.Put("c", "3")
var err error
assert := func() {
if actualValue := m.Keys(); actualValue[0].(string) != "a" || actualValue[1].(string) != "b" || actualValue[2].(string) != "c" {
t.Errorf("Got %v expected %v", actualValue, "[a,b,c]")
}
if actualValue := m.Values(); actualValue[0].(string) != "1" || actualValue[1].(string) != "2" || actualValue[2].(string) != "3" {
t.Errorf("Got %v expected %v", actualValue, "[1,2,3]")
}
if actualValue, expectedValue := m.Size(), 3; actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
for i := 0; i < 10; i++ {
original := NewWith(utils.StringComparator, utils.StringComparator)
original.Put("d", "4")
original.Put("e", "5")
original.Put("c", "3")
original.Put("b", "2")
original.Put("a", "1")
assertSerialization(original, "A", t)
serialized, err := original.ToJSON()
if err != nil {
t.Errorf("Got error %v", err)
}
assertSerialization(original, "B", t)
deserialized := NewWith(utils.StringComparator, utils.StringComparator)
err = deserialized.FromJSON(serialized)
if err != nil {
t.Errorf("Got error %v", err)
}
assertSerialization(deserialized, "C", t)
}
}
assert()
json, err := m.ToJSON()
assert()
err = m.FromJSON(json)
assert()
//noinspection GoBoolExpressions
func assertSerialization(m *Map, txt string, t *testing.T) {
if actualValue := m.Keys(); false ||
actualValue[0].(string) != "a" ||
actualValue[1].(string) != "b" ||
actualValue[2].(string) != "c" ||
actualValue[3].(string) != "d" ||
actualValue[4].(string) != "e" {
t.Errorf("[%s] Got %v expected %v", txt, actualValue, "[a,b,c,d,e]")
}
if actualValue := m.Values(); false ||
actualValue[0].(string) != "1" ||
actualValue[1].(string) != "2" ||
actualValue[2].(string) != "3" ||
actualValue[3].(string) != "4" ||
actualValue[4].(string) != "5" {
t.Errorf("[%s] Got %v expected %v", txt, actualValue, "[1,2,3,4,5]")
}
if actualValue, expectedValue := m.Size(), 5; actualValue != expectedValue {
t.Errorf("[%s] Got %v expected %v", txt, actualValue, expectedValue)
}
}
func benchmarkGet(b *testing.B, m *Map, size int) {

@ -11,12 +11,12 @@ func assertSerializationImplementation() {
var _ containers.JSONDeserializer = (*Map)(nil)
}
// ToJSON outputs the JSON representation of list's elements.
// ToJSON outputs the JSON representation of the map.
func (m *Map) ToJSON() ([]byte, error) {
return m.tree.ToJSON()
}
// FromJSON populates list's elements from the input JSON representation.
// FromJSON populates the map from the input JSON representation.
func (m *Map) FromJSON(data []byte) error {
return m.tree.FromJSON(data)
}

@ -441,34 +441,52 @@ func TestMapIteratorLast(t *testing.T) {
}
func TestMapSerialization(t *testing.T) {
m := NewWithStringComparator()
m.Put("a", "1")
m.Put("b", "2")
m.Put("c", "3")
var err error
assert := func() {
if actualValue := m.Keys(); actualValue[0].(string) != "a" || actualValue[1].(string) != "b" || actualValue[2].(string) != "c" {
t.Errorf("Got %v expected %v", actualValue, "[a,b,c]")
}
if actualValue := m.Values(); actualValue[0].(string) != "1" || actualValue[1].(string) != "2" || actualValue[2].(string) != "3" {
t.Errorf("Got %v expected %v", actualValue, "[1,2,3]")
}
if actualValue, expectedValue := m.Size(), 3; actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
for i := 0; i < 10; i++ {
original := NewWithStringComparator()
original.Put("d", "4")
original.Put("e", "5")
original.Put("c", "3")
original.Put("b", "2")
original.Put("a", "1")
assertSerialization(original, "A", t)
serialized, err := original.ToJSON()
if err != nil {
t.Errorf("Got error %v", err)
}
assertSerialization(original, "B", t)
deserialized := NewWithStringComparator()
err = deserialized.FromJSON(serialized)
if err != nil {
t.Errorf("Got error %v", err)
}
assertSerialization(deserialized, "C", t)
}
}
assert()
json, err := m.ToJSON()
assert()
err = m.FromJSON(json)
assert()
//noinspection GoBoolExpressions
func assertSerialization(m *Map, txt string, t *testing.T) {
if actualValue := m.Keys(); false ||
actualValue[0].(string) != "a" ||
actualValue[1].(string) != "b" ||
actualValue[2].(string) != "c" ||
actualValue[3].(string) != "d" ||
actualValue[4].(string) != "e" {
t.Errorf("[%s] Got %v expected %v", txt, actualValue, "[a,b,c,d,e]")
}
if actualValue := m.Values(); false ||
actualValue[0].(string) != "1" ||
actualValue[1].(string) != "2" ||
actualValue[2].(string) != "3" ||
actualValue[3].(string) != "4" ||
actualValue[4].(string) != "5" {
t.Errorf("[%s] Got %v expected %v", txt, actualValue, "[1,2,3,4,5]")
}
if actualValue, expectedValue := m.Size(), 5; actualValue != expectedValue {
t.Errorf("[%s] Got %v expected %v", txt, actualValue, expectedValue)
}
}
func benchmarkGet(b *testing.B, m *Map, size int) {

@ -14,12 +14,12 @@ func assertSerializationImplementation() {
var _ containers.JSONDeserializer = (*Set)(nil)
}
// ToJSON outputs the JSON representation of list's elements.
// ToJSON outputs the JSON representation of the set.
func (set *Set) ToJSON() ([]byte, error) {
return json.Marshal(set.Values())
}
// FromJSON populates list's elements from the input JSON representation.
// FromJSON populates the set from the input JSON representation.
func (set *Set) FromJSON(data []byte) error {
elements := []interface{}{}
err := json.Unmarshal(data, &elements)

@ -20,7 +20,7 @@ type Iterator struct {
// Iterator returns a stateful iterator whose values can be fetched by an index.
func (set *Set) Iterator() Iterator {
return Iterator{iterator: set.list.Iterator()}
return Iterator{iterator: set.ordering.Iterator()}
}
// Next moves the iterator to the next element and returns true if there was a next element in the container.

@ -2,7 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package linkedhashset implements a set that preserves insertion-order and is backed a hash tables to store values and doubly-linked list to store ordering.
// Package linkedhashset is a set that preserves insertion-order.
//
// It is backed by a hash table to store values and doubly-linked list to store ordering.
//
// Note that insertion-order is not affected if an element is re-inserted into the set.
//
@ -24,8 +26,8 @@ func assertSetImplementation() {
// Set holds elements in go's native map
type Set struct {
items map[interface{}]struct{}
list *doublylinkedlist.List
table map[interface{}]struct{}
ordering *doublylinkedlist.List
}
var itemExists = struct{}{}
@ -33,8 +35,8 @@ var itemExists = struct{}{}
// New instantiates a new empty set and adds the passed values, if any, to the set
func New(values ...interface{}) *Set {
set := &Set{
items: make(map[interface{}]struct{}),
list: doublylinkedlist.New(),
table: make(map[interface{}]struct{}),
ordering: doublylinkedlist.New(),
}
if len(values) > 0 {
set.Add(values...)
@ -46,13 +48,10 @@ func New(values ...interface{}) *Set {
// Note that insertion-order is not affected if an element is re-inserted into the set.
func (set *Set) Add(items ...interface{}) {
for _, item := range items {
if _, contains := set.items[item]; contains {
continue
if _, contains := set.table[item]; !contains {
set.table[item] = itemExists
set.ordering.Append(item)
}
set.items[item] = itemExists
set.list.Append(item)
}
}
@ -60,14 +59,11 @@ func (set *Set) Add(items ...interface{}) {
// Slow operation, worst-case O(n^2).
func (set *Set) Remove(items ...interface{}) {
for _, item := range items {
if _, contains := set.items[item]; !contains {
continue
if _, contains := set.table[item]; contains {
delete(set.table, item)
index := set.ordering.IndexOf(item)
set.ordering.Remove(index)
}
delete(set.items, item)
index := set.list.IndexOf(item)
set.list.Remove(index)
}
}
@ -76,7 +72,7 @@ func (set *Set) Remove(items ...interface{}) {
// Returns true if no arguments are passed at all, i.e. set is always superset of empty set.
func (set *Set) Contains(items ...interface{}) bool {
for _, item := range items {
if _, contains := set.items[item]; !contains {
if _, contains := set.table[item]; !contains {
return false
}
}
@ -90,13 +86,13 @@ func (set *Set) Empty() bool {
// Size returns number of elements within the set.
func (set *Set) Size() int {
return set.list.Size()
return set.ordering.Size()
}
// Clear clears all values in the set.
func (set *Set) Clear() {
set.items = make(map[interface{}]struct{})
set.list.Clear()
set.table = make(map[interface{}]struct{})
set.ordering.Clear()
}
// Values returns all items in the set.

@ -14,12 +14,12 @@ func assertSerializationImplementation() {
var _ containers.JSONDeserializer = (*Set)(nil)
}
// ToJSON outputs the JSON representation of list's elements.
// ToJSON outputs the JSON representation of the set.
func (set *Set) ToJSON() ([]byte, error) {
return json.Marshal(set.Values())
}
// FromJSON populates list's elements from the input JSON representation.
// FromJSON populates the set from the input JSON representation.
func (set *Set) FromJSON(data []byte) error {
elements := []interface{}{}
err := json.Unmarshal(data, &elements)

@ -14,12 +14,12 @@ func assertSerializationImplementation() {
var _ containers.JSONDeserializer = (*Set)(nil)
}
// ToJSON outputs the JSON representation of list's elements.
// ToJSON outputs the JSON representation of the set.
func (set *Set) ToJSON() ([]byte, error) {
return json.Marshal(set.Values())
}
// FromJSON populates list's elements from the input JSON representation.
// FromJSON populates the set from the input JSON representation.
func (set *Set) FromJSON(data []byte) error {
elements := []interface{}{}
err := json.Unmarshal(data, &elements)

@ -11,12 +11,12 @@ func assertSerializationImplementation() {
var _ containers.JSONDeserializer = (*Stack)(nil)
}
// ToJSON outputs the JSON representation of list's elements.
// ToJSON outputs the JSON representation of the stack.
func (stack *Stack) ToJSON() ([]byte, error) {
return stack.list.ToJSON()
}
// FromJSON populates list's elements from the input JSON representation.
// FromJSON populates the stack from the input JSON representation.
func (stack *Stack) FromJSON(data []byte) error {
return stack.list.FromJSON(data)
}

@ -11,12 +11,12 @@ func assertSerializationImplementation() {
var _ containers.JSONDeserializer = (*Stack)(nil)
}
// ToJSON outputs the JSON representation of list's elements.
// ToJSON outputs the JSON representation of the stack.
func (stack *Stack) ToJSON() ([]byte, error) {
return stack.list.ToJSON()
}
// FromJSON populates list's elements from the input JSON representation.
// FromJSON populates the stack from the input JSON representation.
func (stack *Stack) FromJSON(data []byte) error {
return stack.list.FromJSON(data)
}

@ -15,7 +15,7 @@ func assertSerializationImplementation() {
var _ containers.JSONDeserializer = (*Tree)(nil)
}
// ToJSON outputs the JSON representation of list's elements.
// ToJSON outputs the JSON representation of the tree.
func (tree *Tree) ToJSON() ([]byte, error) {
elements := make(map[string]interface{})
it := tree.Iterator()
@ -25,7 +25,7 @@ func (tree *Tree) ToJSON() ([]byte, error) {
return json.Marshal(&elements)
}
// FromJSON populates list's elements from the input JSON representation.
// FromJSON populates the tree from the input JSON representation.
func (tree *Tree) FromJSON(data []byte) error {
elements := make(map[string]interface{})
err := json.Unmarshal(data, &elements)

@ -11,12 +11,12 @@ func assertSerializationImplementation() {
var _ containers.JSONDeserializer = (*Heap)(nil)
}
// ToJSON outputs the JSON representation of list's elements.
// ToJSON outputs the JSON representation of the heap.
func (heap *Heap) ToJSON() ([]byte, error) {
return heap.list.ToJSON()
}
// FromJSON populates list's elements from the input JSON representation.
// FromJSON populates the heap from the input JSON representation.
func (heap *Heap) FromJSON(data []byte) error {
return heap.list.FromJSON(data)
}

@ -15,7 +15,7 @@ func assertSerializationImplementation() {
var _ containers.JSONDeserializer = (*Tree)(nil)
}
// ToJSON outputs the JSON representation of list's elements.
// ToJSON outputs the JSON representation of the tree.
func (tree *Tree) ToJSON() ([]byte, error) {
elements := make(map[string]interface{})
it := tree.Iterator()
@ -25,7 +25,7 @@ func (tree *Tree) ToJSON() ([]byte, error) {
return json.Marshal(&elements)
}
// FromJSON populates list's elements from the input JSON representation.
// FromJSON populates the tree from the input JSON representation.
func (tree *Tree) FromJSON(data []byte) error {
elements := make(map[string]interface{})
err := json.Unmarshal(data, &elements)

@ -15,7 +15,7 @@ func assertSerializationImplementation() {
var _ containers.JSONDeserializer = (*Tree)(nil)
}
// ToJSON outputs the JSON representation of list's elements.
// ToJSON outputs the JSON representation of the tree.
func (tree *Tree) ToJSON() ([]byte, error) {
elements := make(map[string]interface{})
it := tree.Iterator()
@ -25,7 +25,7 @@ func (tree *Tree) ToJSON() ([]byte, error) {
return json.Marshal(&elements)
}
// FromJSON populates list's elements from the input JSON representation.
// FromJSON populates the tree from the input JSON representation.
func (tree *Tree) FromJSON(data []byte) error {
elements := make(map[string]interface{})
err := json.Unmarshal(data, &elements)

Loading…
Cancel
Save