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

Retrieve an arbitrary element from a set without removing it #51461

Closed
wrichert mannequin opened this issue Oct 26, 2009 · 10 comments
Closed

Retrieve an arbitrary element from a set without removing it #51461

wrichert mannequin opened this issue Oct 26, 2009 · 10 comments
Assignees
Labels
interpreter-core (Objects, Python, Grammar, and Parser dirs) type-feature A feature request or enhancement

Comments

@wrichert
Copy link
Mannequin

wrichert mannequin commented Oct 26, 2009

BPO 7212
Nosy @rhettinger, @abalkin, @benjaminp, @ipatrol
Files
  • setobject_get.patch: Patches setobject.[ch] and test_set.py to provide some_set.get()
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = 'https://github.com/rhettinger'
    closed_at = <Date 2010-11-21.23:26:24.470>
    created_at = <Date 2009-10-26.21:07:18.511>
    labels = ['interpreter-core', 'type-feature']
    title = 'Retrieve an arbitrary element from a set without removing it'
    updated_at = <Date 2010-11-21.23:26:24.469>
    user = 'https://bugs.python.org/wrichert'

    bugs.python.org fields:

    activity = <Date 2010-11-21.23:26:24.469>
    actor = 'rhettinger'
    assignee = 'rhettinger'
    closed = True
    closed_date = <Date 2010-11-21.23:26:24.470>
    closer = 'rhettinger'
    components = ['Interpreter Core']
    creation = <Date 2009-10-26.21:07:18.511>
    creator = 'wrichert'
    dependencies = []
    files = ['15211']
    hgrepos = []
    issue_num = 7212
    keywords = ['patch']
    message_count = 10.0
    messages = ['94508', '94511', '94548', '94599', '94613', '94938', '94939', '106592', '106593', '106594']
    nosy_count = 5.0
    nosy_names = ['rhettinger', 'belopolsky', 'benjamin.peterson', 'wrichert', 'ipatrol']
    pr_nums = []
    priority = 'low'
    resolution = 'rejected'
    stage = None
    status = 'closed'
    superseder = None
    type = 'enhancement'
    url = 'https://bugs.python.org/issue7212'
    versions = ['Python 2.7', 'Python 3.2']

    @wrichert
    Copy link
    Mannequin Author

    wrichert mannequin commented Oct 26, 2009

    Sometimes, a non-removing pop() is needed. In current Python versions,
    it can achieved by one of the following ways:

    x = some_set.pop()
    some_set.add(x)

    for x in some_set:
    break

    x = iter(some_set).next()

    More native and clean would, however, be
    some_set.get()

    The attached patch does this for set(). If this is accepted by the
    community, frozenset should be extended as well.

    @wrichert wrichert mannequin added stdlib Python modules in the Lib dir type-feature A feature request or enhancement labels Oct 26, 2009
    @rhettinger rhettinger self-assigned this Oct 26, 2009
    @benjaminp
    Copy link
    Contributor

    Without tests, this patch is unacceptable.

    @wrichert
    Copy link
    Mannequin Author

    wrichert mannequin commented Oct 27, 2009

    added tests for get() to test_set.py

    @abalkin
    Copy link
    Member

    abalkin commented Oct 28, 2009

    Any reason you don't want to call set_next from set_get?

    I would say

    static PyObject *
    set_get(PySetObject *so)
    {
    	register Py_ssize_t pos = 0;
    	register setentry *entry;
            if (set_next(so, &pos, &entry)) {
                  Py_INCREF(entry->key);
                  return entry->key;
            }
            /* set appropriate error */
            return NULL;
    }

    BTW, what your patch is supposed to do on set().get()?
    }

    @wrichert
    Copy link
    Mannequin Author

    wrichert mannequin commented Oct 28, 2009

    No particular reason, besides that it is ripped off of pop().

    Your solution (omitting "register") gives the same performance. Looks
    cleaner, of course.

    The patch tries to provide a clean way of "for x in some_set: break", as
    explained above. See the recent python-dev mailing list musings.

    @rhettinger
    Copy link
    Contributor

    After a long discussion on python-dev, this proposal is rejected in
    favor of adding documentation notes on the ways to non-destructively
    retrieve an arbitrary item from a set or frozenset.

    Here is an except from the end of the thread:

    [Steven D'Aprano]

    > Anyway, given the level of opposition to the suggestion, I'm no longer
    > willing to carry the flag for it. If anyone else -- perhaps the OP --
    > feels they want to take it any further, be my guest.

    [geremy condra]

    I've said before that I'd like there to be one, standard way of
    doing this. A function call- set.pick() seems reasonably named
    to me- is probably the cleanest way to do that. Absent that,
    an example in the docs that illustrates the preferred idiom
    would be great.

    [Raymond]
    Summarizing my opposition to a new set method:

    1. there already are at least two succinct ways to get the same effect
    2. those ways work with any container, not just sets
    3. set implementations in other languages show that this isn't needed.
    4. there is value to keeping the API compact
    5. isn't needed for optimization (selecting the same value in a loop
      makes no sense)
    6. absence of real-world code examples that would be meaningfully improved

    [Terry Reedy]
    Agreed

    [Raymond]
    I would be happy to add an example to the docs so that this thread
    can finally end.

    [Eric Smith]
    Please do!

    [Terry Reedy]
    Yes!
    '''

    Leaving this open until I've done the documentation patch.

    @abalkin
    Copy link
    Member

    abalkin commented Nov 5, 2009

    I don't want to pollute python-dev with more hopeless ideas, but I wonder
    if itertools could grow an efficient C-implemented

    def first(collection):
       return next(iter(collection))

    On the other hand, it probably belongs to recipes more than stdlib. This
    is not really an iterator tool after all.

    @ipatrol
    Copy link
    Mannequin

    ipatrol mannequin commented May 27, 2010

    I still see a use in this. I like to use sets for lists of servers or mirrors. There is no compelling reason *not* to add a get() or pick() method, as described in http://en.wikipedia.org/wiki/Set_%28computer_science%29. Sets could be used for many things that lists are currently used for. I request for this to be reopened given the lapse since any action on this.

    @ipatrol ipatrol mannequin added interpreter-core (Objects, Python, Grammar, and Parser dirs) and removed stdlib Python modules in the Lib dir labels May 27, 2010
    @ipatrol
    Copy link
    Mannequin

    ipatrol mannequin commented May 27, 2010

    I support http://bugs.python.org/msg94599 with a check to see if the length is 0, and rename it pick (based on the generic programming and mathematical literature).

    @rhettinger
    Copy link
    Contributor

    Use set.pop().

    Or if you don't want mutation, then use next(iter(s)) or next(iter(s),default). This technique also works for any collection including dicts and deques and whatnot.

    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    interpreter-core (Objects, Python, Grammar, and Parser dirs) type-feature A feature request or enhancement
    Projects
    None yet
    Development

    No branches or pull requests

    3 participants