I think that `OrderedDict.items().__getitem__` should be implemented, to solve this ugliness: http://stackoverflow.com/questions/21062781/shortest-way-to-get-first-item-o... What do you think? Thanks, Ram.
On Sun, Jan 12, 2014 at 1:18 AM, Ram Rachum
I think that `OrderedDict.items().__getitem__` should be implemented, to solve this ugliness:
http://stackoverflow.com/questions/21062781/shortest-way-to-get-first-item-o...
What do you think?
Well, the first problem with that is that __getitem__ already exists, and it's dict-style :) So you can't fetch out an item by its position that way. But suppose you create a method that returns the Nth element. The implementation in CPython 3.4 is a linked list, so getting an arbitrary element by index would be quite inefficient. Getting specifically the first can be done either with what you see in that link (it could be made a tiny bit shorter, but not much), but anything else would effectively entail iterating over the whole thing until you get to that position, so you may as well do that explicitly. Alternatively, if you're okay with it being a destructive operation, you can use popitem() to snag the first (or last, if you wish) key/value pair. ChrisA
Ram Rachum wrote:
I think that `OrderedDict.items().__getitem__` should be implemented, to solve this ugliness:
http://stackoverflow.com/questions/21062781/shortest-way-to-get-first- item-of-ordereddict-in-python-3
What do you think?
I think an O(N) __getitem__() is even uglier. Also, you should have really compelling reasons for allowing the interfaces of dict.items() and OrderedDict.items() to diverge. Personally, I'd use a helper function def first(items): for item in items: return item raise ValueError("No first item in an empty sequence") and I don't understand why user thefourtheye is downvoted. Hiding a non- obvious if small piece of code behind a self-explaining name seems like good programming practice.
On 11/01/2014 14:18, Ram Rachum wrote:
I think that `OrderedDict.items().__getitem__` should be implemented, to solve this ugliness:
http://stackoverflow.com/questions/21062781/shortest-way-to-get-first-item-o...
What do you think?
Thanks, Ram.
Use the more_itertools first function. -- My fellow Pythonistas, ask not what our language can do for you, ask what you can do for our language. Mark Lawrence
Based on your popitem idea:
get_first = lambda d: d.copy().popitem()
get_last = lambda d: d.copy().popitem(last=True)
On Sat, Jan 11, 2014 at 8:36 AM, Chris Angelico
On Sun, Jan 12, 2014 at 1:18 AM, Ram Rachum
wrote: I think that `OrderedDict.items().__getitem__` should be implemented, to solve this ugliness:
http://stackoverflow.com/questions/21062781/shortest-way-to-get-first-item-o...
What do you think?
Well, the first problem with that is that __getitem__ already exists, and it's dict-style :) So you can't fetch out an item by its position that way. But suppose you create a method that returns the Nth element.
The implementation in CPython 3.4 is a linked list, so getting an arbitrary element by index would be quite inefficient. Getting specifically the first can be done either with what you see in that link (it could be made a tiny bit shorter, but not much), but anything else would effectively entail iterating over the whole thing until you get to that position, so you may as well do that explicitly. Alternatively, if you're okay with it being a destructive operation, you can use popitem() to snag the first (or last, if you wish) key/value pair.
ChrisA _______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
-- Ryan When your hammer is C++, everything begins to look like a thumb.
Why not: get_first = lambda d: next(iter(d.items())) No need for a full copy of the dict. On 01/11/2014 09:51 PM, Ryan Gonzalez wrote:
Based on your popitem idea:
get_first = lambda d: d.copy().popitem() get_last = lambda d: d.copy().popitem(last=True)
On Sat, Jan 11, 2014 at 8:36 AM, Chris Angelico
mailto:rosuav@gmail.com> wrote: On Sun, Jan 12, 2014 at 1:18 AM, Ram Rachum
mailto:ram.rachum@gmail.com> wrote: > I think that `OrderedDict.items().__getitem__` should be implemented, to > solve this ugliness: > > http://stackoverflow.com/questions/21062781/shortest-way-to-get-first-item-o... > > What do you think? Well, the first problem with that is that __getitem__ already exists, and it's dict-style :) So you can't fetch out an item by its position that way. But suppose you create a method that returns the Nth element.
The implementation in CPython 3.4 is a linked list, so getting an arbitrary element by index would be quite inefficient. Getting specifically the first can be done either with what you see in that link (it could be made a tiny bit shorter, but not much), but anything else would effectively entail iterating over the whole thing until you get to that position, so you may as well do that explicitly. Alternatively, if you're okay with it being a destructive operation, you can use popitem() to snag the first (or last, if you wish) key/value pair.
ChrisA _______________________________________________ Python-ideas mailing list Python-ideas@python.org mailto:Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
-- Ryan When your hammer is C++, everything begins to look like a thumb.
_______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
On Sun, Jan 12, 2014 at 8:47 AM, Mathias Panzenböck
Why not:
get_first = lambda d: next(iter(d.items()))
No need for a full copy of the dict.
On 01/11/2014 09:51 PM, Ryan Gonzalez wrote:
Based on your popitem idea:
get_first = lambda d: d.copy().popitem() get_last = lambda d: d.copy().popitem(last=True)
Oh right. Yeah, copy(). So this isn't destructive, but as Mathias says, it's probably inefficient. (I say "probably" because it's theoretically possible to optimize the copy operation - but I don't see anything like that in the source code.) ChrisA
On 11/01/2014 22:03, Chris Angelico wrote:
On Sun, Jan 12, 2014 at 8:47 AM, Mathias Panzenböck
wrote: Why not:
get_first = lambda d: next(iter(d.items()))
No need for a full copy of the dict.
On 01/11/2014 09:51 PM, Ryan Gonzalez wrote:
Based on your popitem idea:
get_first = lambda d: d.copy().popitem() get_last = lambda d: d.copy().popitem(last=True)
Oh right. Yeah, copy(). So this isn't destructive, but as Mathias says, it's probably inefficient. (I say "probably" because it's theoretically possible to optimize the copy operation - but I don't see anything like that in the source code.)
ChrisA
Surely a shallow copy isn't guaranteed to work properly in all cases anyway? copy(...) D.copy() -> a shallow copy of D -- My fellow Pythonistas, ask not what our language can do for you, ask what you can do for our language. Mark Lawrence
On Sun, Jan 12, 2014 at 9:32 AM, Mark Lawrence
Surely a shallow copy isn't guaranteed to work properly in all cases anyway?
copy(...) D.copy() -> a shallow copy of D
A shallow copy is sufficient if it's about to mutate the dictionary itself (popitem). It's the right semantics... just the wrong complexity, as it's expensive on large dictionaries :) ChrisA
It is pretty inefficient. As for getting the last item, however, I think
something like that might end up the best.
And, you've gotta admit, it isn't bad for a 30-second solution with no real
planning whatsoever.
On Sat, Jan 11, 2014 at 4:03 PM, Chris Angelico
On Sun, Jan 12, 2014 at 8:47 AM, Mathias Panzenböck
wrote: Why not:
get_first = lambda d: next(iter(d.items()))
No need for a full copy of the dict.
On 01/11/2014 09:51 PM, Ryan Gonzalez wrote:
Based on your popitem idea:
get_first = lambda d: d.copy().popitem() get_last = lambda d: d.copy().popitem(last=True)
Oh right. Yeah, copy(). So this isn't destructive, but as Mathias says, it's probably inefficient. (I say "probably" because it's theoretically possible to optimize the copy operation - but I don't see anything like that in the source code.)
ChrisA _______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
-- Ryan When your hammer is C++, everything begins to look like a thumb.
On Sun, Jan 12, 2014 at 10:01 AM, Ryan Gonzalez
It is pretty inefficient. As for getting the last item, however, I think something like that might end up the best.
For getting the last item, reversed() should be as fast as iter() is for getting the first - at least in CPython 3.4, which is what I was looking at.
And, you've gotta admit, it isn't bad for a 30-second solution with no real planning whatsoever.
There is that :) ChrisA
On 01/11/2014 03:36 PM, Chris Angelico wrote:
On Sun, Jan 12, 2014 at 1:18 AM, Ram Rachum
wrote: I think that `OrderedDict.items().__getitem__` should be implemented, to solve this ugliness:
http://stackoverflow.com/questions/21062781/shortest-way-to-get-first-item-o...
What do you think?
Well, the first problem with that is that __getitem__ already exists, and it's dict-style :) So you can't fetch out an item by its position that way. But suppose you create a method that returns the Nth element.
The implementation in CPython 3.4 is a linked list, so getting an arbitrary element by index would be quite inefficient. [...]
I have occasionnally implemented ordered sets or associative arrays in a really simple, stupid manner [1]: just store the items or entries (pairs) in an array (instead of, say, anywhere in memory at the allocator's convenience), in addition to the usual array of "buckets". About efficiency, there is a kind of balance of benefits & costs: In average, common operations should in principle be faster due to memory compacity and consequent cache usage. No cost in memory size (entries must be somewhere anyway). There is a little cost when the whole data structure grows, since now 2 arrays have to be resized up; to mitigate, i provide a 'predim' (predimension) method that avoids most growing operations. The point is that now entries form an array that keeps insertion order, can be traversed and even indexed. An issue, however, like for any flexible-size array, is with item deletion. I don't delete at once, which would require compacting the array everytime an entry is removed, instead just mark entries as deleted. Whenever a big proportion of items are removed [2], there is automatic compaction. But with such a trick, indexing in then invalid (and prevented); to retrieve this indexing feature, if items have been deleted, clients must first run a 'compact' method, that actually removes all deleted items at once (and if many worth it resizes down). For traversal however, there is no issue: the implementation just needs to skip items marked as deleted. I have no idea whether such a stupid way to make ordered sets/dicts is compatible with the present requirements or implementation for python's ordereddicts (but suspect it is not). And I guess the constraint on indexing does not really fit the python way, in that an implementation constraint leaks into the client interface. Just wanted however to say a few words about that scheme due its simplicity and practicality. Comments welcome. Denis [1] The common need is usually for what I call "mod tables", used as symbol tables: a mod table is like a hash table, but with keys beeing unsigned ints, thus there is no hash, instead plain modulo. This makes a sort of sparse array, but ordered. Numeric keys actually represent interned strings which themselves are keys in symbol tables (scopes, namespaces...). [2] To avoid a kind of threashold effect, compaction happens when the count of items is less than 3/8 of capacity, not half of it. There must be an hysteresis (difference of threashold to resize up versus down) to avoid instability in the hypothetical case where the count of items is close to a resizing capacity and items are constantly beeing put & removed.
On Sat, Jan 11, 2014 at 04:36:49PM +0100, Peter Otten wrote:
Ram Rachum wrote:
I think that `OrderedDict.items().__getitem__` should be implemented, to solve this ugliness:
http://stackoverflow.com/questions/21062781/shortest-way-to-get-first- item-of-ordereddict-in-python-3
What do you think?
I think an O(N) __getitem__() is even uglier. Also, you should have really compelling reasons for allowing the interfaces of dict.items() and OrderedDict.items() to diverge.
Agreed, but I do think that OrderedDict could be more helpful here. I haven't wanted to get the first item before but I have wanted to get the last without popping it off. Since this can be provided in O(1) I think it would make a reasonable addition as a property of OrderedDict: @property def last(self): if not self: raise KEyError('dictionary is empty') return self.__root.prev Just returning the key sufficient but in my own use cases I would have wanted the whole item which you could easily do: @property def lastitem(self): if not self: raise KEyError('dictionary is empty') key = self.__root.prev return key, self.__map[key] Oscar
participants (8)
-
Chris Angelico
-
Mark Lawrence
-
Mathias Panzenböck
-
Oscar Benjamin
-
Peter Otten
-
Ram Rachum
-
Ryan Gonzalez
-
spir