Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions examples/linkedhashset/linkedhashset.go
Original file line number Diff line number Diff line change
@@ -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/sets/linkedhashset"

// LinkedHashSetExample to demonstrate basic usage of LinkedHashSet
func main() {
set := linkedhashset.New() // empty
set.Add(5) // 5
set.Add(4, 4, 3, 2, 1) // 5, 4, 3, 2, 1 (in insertion-order, duplicates ignored)
set.Remove(4) // 5, 3, 2, 1 (in insertion-order)
set.Remove(2, 3) // 5, 1 (in insertion-order)
set.Contains(1) // true
set.Contains(1, 5) // true
set.Contains(1, 6) // false
_ = set.Values() // []int{5, 1} (in insertion-order)
set.Clear() // empty
set.Empty() // true
set.Size() // 0
}
2 changes: 1 addition & 1 deletion lists/arraylist/arraylist.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func (list *List) Get(index int) (interface{}, bool) {
return list.elements[index], true
}

// Remove removes one or more elements from the list with the supplied indices.
// Remove removes the element at the given index from the list.
func (list *List) Remove(index int) {

if !list.withinRange(index) {
Expand Down
2 changes: 1 addition & 1 deletion lists/doublylinkedlist/doublylinkedlist.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ func (list *List) Get(index int) (interface{}, bool) {
return element.value, true
}

// Remove removes one or more elements from the list with the supplied indices.
// Remove removes the element at the given index from the list.
func (list *List) Remove(index int) {

if !list.withinRange(index) {
Expand Down
2 changes: 1 addition & 1 deletion lists/singlylinkedlist/singlylinkedlist.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ func (list *List) Get(index int) (interface{}, bool) {
return element.value, true
}

// Remove removes one or more elements from the list with the supplied indices.
// Remove removes the element at the given index from the list.
func (list *List) Remove(index int) {

if !list.withinRange(index) {
Expand Down
79 changes: 79 additions & 0 deletions sets/linkedhashset/enumerable.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// 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 linkedhashset

import "github.com/emirpasic/gods/containers"

func assertEnumerableImplementation() {
var _ containers.EnumerableWithIndex = (*Set)(nil)
}

// Each calls the given function once for each element, passing that element's index and value.
func (set *Set) Each(f func(index int, value interface{})) {
iterator := set.Iterator()
for iterator.Next() {
f(iterator.Index(), iterator.Value())
}
}

// Map invokes the given function once for each element and returns a
// container containing the values returned by the given function.
func (set *Set) Map(f func(index int, value interface{}) interface{}) *Set {
newSet := New()
iterator := set.Iterator()
for iterator.Next() {
newSet.Add(f(iterator.Index(), iterator.Value()))
}
return newSet
}

// Select returns a new container containing all elements for which the given function returns a true value.
func (set *Set) Select(f func(index int, value interface{}) bool) *Set {
newSet := New()
iterator := set.Iterator()
for iterator.Next() {
if f(iterator.Index(), iterator.Value()) {
newSet.Add(iterator.Value())
}
}
return newSet
}

// Any passes each element of the container to the given function and
// returns true if the function ever returns true for any element.
func (set *Set) Any(f func(index int, value interface{}) bool) bool {
iterator := set.Iterator()
for iterator.Next() {
if f(iterator.Index(), 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 (set *Set) All(f func(index int, value interface{}) bool) bool {
iterator := set.Iterator()
for iterator.Next() {
if !f(iterator.Index(), iterator.Value()) {
return false
}
}
return true
}

// Find passes each element of the container to the given function and returns
// the first (index,value) for which the function is true or -1,nil otherwise
// if no element matches the criteria.
func (set *Set) Find(f func(index int, value interface{}) bool) (int, interface{}) {
iterator := set.Iterator()
for iterator.Next() {
if f(iterator.Index(), iterator.Value()) {
return iterator.Index(), iterator.Value()
}
}
return -1, nil
}
77 changes: 77 additions & 0 deletions sets/linkedhashset/iterator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// 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 linkedhashset

import (
"github.com/emirpasic/gods/containers"
"github.com/emirpasic/gods/lists/doublylinkedlist"
)

func assertIteratorImplementation() {
var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil)
}

// Iterator holding the iterator's state
type Iterator struct {
iterator doublylinkedlist.Iterator
}

// Iterator returns a stateful iterator whose values can be fetched by an index.
func (set *Set) Iterator() Iterator {
return Iterator{iterator: set.list.Iterator()}
}

// 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 index and value can be retrieved by Index() 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 index and value can be retrieved by Index() 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{} {
return iterator.iterator.Value()
}

// Index returns the current element's index.
// Does not modify the state of the iterator.
func (iterator *Iterator) Index() int {
return iterator.iterator.Index()
}

// 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 index and value can be retrieved by Index() 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 index and value can be retrieved by Index() and Value().
// Modifies the state of the iterator.
func (iterator *Iterator) Last() bool {
return iterator.iterator.Last()
}
118 changes: 118 additions & 0 deletions sets/linkedhashset/linkedhashset.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
// 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 linkedhashset implements a set that preserves insertion-order and is backed a hash tables 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.
//
// Structure is not thread safe.
//
// References: http://en.wikipedia.org/wiki/Set_%28abstract_data_type%29
package linkedhashset

import (
"fmt"
"github.com/emirpasic/gods/lists/doublylinkedlist"
"github.com/emirpasic/gods/sets"
"strings"
)

func assertSetImplementation() {
var _ sets.Set = (*Set)(nil)
}

// Set holds elements in go's native map
type Set struct {
items map[interface{}]struct{}
list *doublylinkedlist.List
}

var itemExists = struct{}{}

// New instantiates a new empty set
func New() *Set {
return &Set{
items: make(map[interface{}]struct{}),
list: doublylinkedlist.New(),
}
}

// Add adds the items (one or more) to the 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
}

set.items[item] = itemExists
set.list.Append(item)
}
}

// Remove removes the items (one or more) from the set.
// Slow operation, worst-case O(n^2).
func (set *Set) Remove(items ...interface{}) {
for _, item := range items {

if _, contains := set.items[item]; !contains {
continue
}

delete(set.items, item)
index := set.list.IndexOf(item)
set.list.Remove(index)
}
}

// Contains check if items (one or more) are present in the set.
// All items have to be present in the set for the method to return true.
// 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 {
return false
}
}
return true
}

// Empty returns true if set does not contain any elements.
func (set *Set) Empty() bool {
return set.Size() == 0
}

// Size returns number of elements within the set.
func (set *Set) Size() int {
return set.list.Size()
}

// Clear clears all values in the set.
func (set *Set) Clear() {
set.items = make(map[interface{}]struct{})
set.list.Clear()
}

// Values returns all items in the set.
func (set *Set) Values() []interface{} {
values := make([]interface{}, set.Size())
it := set.Iterator()
for it.Next() {
values[it.Index()] = it.Value()
}
return values
}

// String returns a string representation of container
func (set *Set) String() string {
str := "LinkedHashSet\n"
items := []string{}
it := set.Iterator()
for it.Next() {
items = append(items, fmt.Sprintf("%v", it.Value()))
}
str += strings.Join(items, ", ")
return str
}
Loading