[Python-ideas] Add dict.getkey() and set.get()
Andrew Barnert
abarnert at yahoo.com
Mon Sep 16 09:25:57 CEST 2013
On Sep 15, 2013, at 18:39, Terry Reedy <tjreedy at udel.edu> wrote:
> On 9/15/2013 8:30 PM, Steven D'Aprano wrote:
>> On Sun, Sep 15, 2013 at 09:02:33PM +0100, Oscar Benjamin wrote:
>>
>>> I don't know whether this is relying on undefined behaviour but the
>>> following is O(1) and seems to work:
>>>
>>>>>> def canonical_key(d, k):
>>> ... k, = {k} & d.keys()
>>> ... return k
>>> ...
>>
>> I'm pretty sure that (1) it relies on implementation-specific behaviour,
>> and (2) it's O(N), not O(1).
>>
>> The implementation-specific part is whether & takes the key from the
>> left-hand or right-hand operand when the keys are equal. For example, in
>> Python 3.3:
>>
>> py> {1} & {1.0}
>> {1.0}
>> py> {1} & {1.0, 2.0}
>> {1}
>>
>> And surely it's O(N) -- to be precise, O(M+N) -- because & has to walk
>> all the keys in both operands?
>
> No, just the keys in one of the operands. That can be chosen to be the smaller of the two, making it O(min(M,N)). I believe that is what is happening above: the operands are switched when the first is smaller. I know there was a tracker issue that added this optimization.
But it doesn't happen for dict_keys, because that ends up calling intersection_update on a copy of the left operand, which means it always walks the right operand (in this case the dict_keys itself), instead of calling set_intersection, as it would on two sets.
At any rate, whenever this does what's desired, it does a linear walk of all keys in the dict; conversely, any variant that only walks the single key in {k} ends up returning {k} instead of what you were looking for.
More information about the Python-ideas
mailing list