Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

What do you think about Enumerator? #8

Closed
wildfire810 opened this issue Jun 12, 2016 · 13 comments
Closed

What do you think about Enumerator? #8

wildfire810 opened this issue Jun 12, 2016 · 13 comments

Comments

@wildfire810
Copy link

wildfire810 commented Jun 12, 2016

What do you think about Enumerator?
In offical library, there is "container/list", it contains Element, that can take values one by one.
I think it takes less complex then every time find it.

@emirpasic
Copy link
Owner

emirpasic commented Jun 12, 2016

Enumerator similar to C++ STL iterators, Ruby's Enumerator and Java's Enumeration classes that allows for internal and external iteration? I wanted to do that from the start, but never found the time for it. I think that's a great addition and allows for writing more optimized code! Let me first do some research on how other languages had implemented it, because this would require a large change and only ordered collection can support this feature.

@wildfire810
Copy link
Author

great work

@emirpasic
Copy link
Owner

There are a few ways of implementing this.

I'd exclude the channels approach (inc. buffered channels) for performance reasons (albeit the channels have gotten faster) and (mis/over)use thereof. People seem to open a channel nowadays to add two numbers together and it feels like going after a fly with a bazooka just because bazookas are cool.

Also I am uneasy about the performance of the closurer approach .

So that leaves me with two patterns:

  • Stateful iterator (Java style)
  • Callback "iterator"/enumerator (Ruby and JavaScript style)

Despite being inclined towards Ruby's readability (dreaming of each/map/select/etc.), I will run some tests on both approaches this weekend and see which one works and looks better.

Thanks for pointing this out, it will be great addition to this project 👍

@emirpasic
Copy link
Owner

@wildfire810

I started working on enumerables and would appreciate your opinion if you would use this:

import "github.com/emirpasic/gods/lists/arraylist"

func main() {
    list := arraylist.New()
    list.Add("a", "b", "c") 

    list.Each(func(index interface{}, value interface{}) {
        fmt.Println(value)
    })

    fmt.Println(list.Map(func(index interface{}, value interface{}) interface{} {
        return value
    }))

    fmt.Println(list.Select(func(index interface{}, value interface{}) bool {
        return value.(string) >= "a" && value.(string) <= "b"
    }))

    fmt.Println(list.Any(func(index interface{}, value interface{}) bool {
        return value.(string) == "c"
    }))

    fmt.Println(list.All(func(index interface{}, value interface{}) bool {
        return value.(string) >= "a" && value.(string) <= "c"
    }))

    fmt.Println(list.Find(func(index interface{}, value interface{}) bool {
        return value.(string) == "c"
    }))
}

Currently the enumrable interface supports the following:

package enumerable

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

type Interface interface {
    // Calls the given function once for each element, passing that element's index(key) and value.
    Each(func(index interface{}, value interface{}))

    // Invokes the given function once for each element and returns a
    // container containing the values returned by the given function.
    Map(func(index interface{}, value interface{}) interface{}) containers.Interface

    // Returns a new container containing all elements for which the given function returns a true value.
    Select(func(index interface{}, value interface{}) bool) containers.Interface

    // Passes each element of the collection to the given function and
    // returns true if the function ever returns true for any element.
    Any(func(index interface{}, value interface{}) bool) bool

    // Passes each element of the collection to the given function and
    // returns true if the function returns true for all elements.
    All(func(index interface{}, value interface{}) bool) bool

    // Passes each element of the collection to the given function and returns
    // the first for which the function is true or nil,nil otherwise if no element
    // matches the criteria.
    Find(func(index interface{}, value interface{}) bool) (index interface{}, value interface{})
}

Current implementation is on enumerable branch and is purely Ruby inspired for readability. Only arraylist currently implemented, pending opinion if this is usable.

@wildfire810
Copy link
Author

I think it's ok.
But ciuld you think about cpp iterator?
If we want to use it throw the Each func on above, we must use channel to yield the loop.
If we want to use list1[x] list2[x] and so on...one by one, we can not break the loop and continue it unless using channel.
Or we use get func, the performance will be degenerate

@emirpasic
Copy link
Owner

Good point and I hope you won't need channels for this.
So I think I'll keep the above Ruby inspired Enumerable and I'll also add the c++ stateful iterators:

it := list.Iterator()
for it.Next() {
    value := it.Value()
    ...
}

Does this work for you?

For multiple lists it goes the same:

it1 := list1.Iterator()
it2 := list2.Iterator()
for it1.Next() && it2.Next() {
    value1 := it1.Value()
    value2 := it1.Value()
    ...
}

I think that's the cleanest pattern for god's containers, since there is no operator overloading.

@wildfire810
Copy link
Author

I think it's very good!

@wildfire810
Copy link
Author

Can add insert func with iter?

@emirpasic
Copy link
Owner

Can add insert func with iter?

Insert func is already on master, thus I closed that issue:
List's insert definition
Example in test

Did you mean the above or the possibility to insert values into list during iteration (which would be hard)?

@emirpasic
Copy link
Owner

This is almost done, PR is up, but need to update with examples and documentatio. Then I will merge it, for now you can checkout #12 if that's OK with you. Thanks again for giving me inspiration to do this :)

@wildfire810
Copy link
Author

thanks a lot for your work:)
with pleasure

@wildfire810
Copy link
Author

Is there reverse Iterator?

@emirpasic
Copy link
Owner

Is there reverse Iterator?

No, not yet, but it would be good to have, especially for some data structures where that is natural. For singly linked list that wouldn't be feasible, but for doubly linked list it would make absolute sense.

Can you open a new issue for reverse iterators please, because I am merging the PR that closes this issue. I'll tackle the reverse iterators in another issue + PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants