RepugNaNt
I had a disgusting thought just now. I needed to have some Python code check whether a dictionary contains a particular key/value pair. The obvious approach,
if dictionary[key] == value:
isn't sufficient, because I need to not throw an exception if the dictionary doesn't contain any mapping for that key at all.
An obvious way is to use a second clause to handle the latter case, so you end up writing
if key in dictionary and dictionary[key] == value:
But that's unpleasantly verbose, and also undesirable if dictionary or key is a complicated expression or one with side effects. So I wondered if we could do better.
Another possibility is to use the get() method of Python dictionaries, which lets you specify a default return value if the dictionary hasn't got the key in question. So you might say, for instance,
if dictionary.get(key, None) == value:
But in order to be able to do that, you have to be able to think of a default that will guarantee to compare unequal to value; for instance here, what if the value is None? If you know something about value (e.g. its type) then this is probably feasible one way or another, but one can imagine more general situations in which that wouldn't be the case.
I think the right answer, in fact, is to write
if (key, value) in dictionary.viewitems():
where viewitems() is a standard method which presents the dictionary as if it were a set of ordered pairs. (You could also use dictionary.items(), which would be semantically equivalent, but much slower due to constructing an explicit list and then iterating along it.)
But before I found the viewitems() method, I thought a bit harder about the get() approach. Perhaps, I thought, I could define a class with a comparison method that always returned false, so that an instance of that class would compare unequal to anything, including itself.
And then, as I thought the phrase ‘compare unequal to anything, including itself’, a stray neuron fired in my head. I think this would work pretty reliably:
if dictionary.get(key, float('nan')) == value:
and its only downside is that it is the most disgusting thing ever! :-)

no subject
Especially the way you have to say float('nan') - surely there's a better way of getting hold of NaN??
no subject
no subject
no subject
no subject
In C++, what you want is relatively straightforward:
auto i = dictionary.find(key); if (i!=dictionary.end() && *i==value) {I assume Python has nothing similar to C++ STL's iterators to help you?no subject
…and you'd have to name the iterator's type explicitly before C++11.
…and in C++ you might be using an associative container that can map the same key to multiple values, in which case you'd need to know whether you wanted all entries with that key to have the specified value or at least one.
no subject
class d_items: def __init__(self, d): self.__d = d def __len__(self): return len(self.__d) def __contains__(self, (key, value)): return key in self.__d and self.__d[key] == value (etc.)which suggests that that sort of optimisation (if you can really call it that) is what is in mind.
no subject
The Python help says that if
Dis a dictionary thenD.viewitems()returns "a set-like object providing a view onD's items", which seems to me like a clear hint that it's not going to the effort of physically constructing an actual Python set object but is instead providing a duck-typed thing that behaves like a set. So I would expect it to DTRT, performance-wise.In C++, what you want is relatively straightforward:
It's straightforward if you're happy to use a whole statement and a variable declaration! All of the Python idioms I suggest above, including the two-clause one that seems to me most analogous to your C++ version, can be used in the middle of a larger expression without having to stop to declare local variables first.
no subject
viewitems()answers queries of this type quickly as I'd expected. I just did this:and there was a delay of a second or so when constructing the dictionary in the first place, and when testing viaitems(), but testing viaviewitems()was instant.no subject
It seems what you actually want is an operator built into the language which does something like:
#define MACRO(lhs,rhs) (lhs) && (lhs rhs)
MACRO(dictionary[key],==value)
but without the ugliness of being a macro. But I don't know if any language does have that?
no subject
cockcook one up in Lisp :-)no subject
no subject
no subject
no subject
Delving deeper, I've always felt the STL gets things significantly wrong with iterators. Rather than iterators, it should be dealing in ranges, things you can dereference, increment and test for truth. Amongst the many more major advantages, that would mean one could do:
if (auto r = dictionary.find(key)) if (r->second==value)You're still doing two steps, but at least they nest and scope tidily!
no subject
Hm. I guess I thought "calling a member function with no side effects, doing a comparison, then calling the same function again with the same arguments" was one of the most obvious optimisations, but I guess (a) "no side effects" isn't obvious (if this is in a function, dictionary should probably be passed as a const reference, and then it will use a const version of find, assuming there is one, but I guess even then, if it's in a library, there's no way for the calling code to know it wasn't modifying some global or mutable state) and (b) and even if it were I know really, really little about what compilers actually do in practice, so you're probably right.
no subject
Also, it's easy to write inherently efficient code that uses std::map, so compiler authors might not have seen optimising inefficient uses as a priority.
no subject
I feel silly, because I've been generally trying to prioritise clarity over micro-optimisation, which normally means _not_ using an extra local variable (unless it makes it equally or more clear, as in some loops, or is necessary, as in cpu-bound inner loops) and now I wonder if I'm wrong.
I wonder, _should_ C++ be able to apply "const" somewhere to say "this function doesn't change any global or static state"? Would it help?
no subject
constkeyword when defining a class method, indicating that it's permissible to apply the method to aconstinstance of that class.But the semantics aren't quite the same. It's easy to imagine functions that don't change any state and are safe to apply to a const object, but which nonetheless don't reliably return the same value if called twice. (For instance, a function that returns the number of nanoseconds until the object's expiry date, or one that returns the current contents of the file whose pathname is stored in the object. eta: or, come to think of it, a function that simply dereferences a pointer stored in the object! Much simpler, and no need to invoke the mysterious concurrency of the real world :-)
So you actually want a marker less like "const" and more like "pure", indicating that whatever the function does has no side effects and depends on only the obvious input values, so that the optimiser is permitted to assume that apparently identical calls to it are actually identical and fold them together.
no subject
Apart from overload resolution, I believe there is never any circumstance in which changing the constness of a function would affect how it compiled. In the very most extreme case, it might const_cast<MyType *>(this).
Conversely, except in the actually-quite-common case where polymorphic objects or function pointers impinge, the compiler could, in theory, recursively annotate functions with their purity. But take a look at just how deep the call stack gets when you say if (dictionary.count(key) && dictionary[key]==value), having regard to all the std::pair accessors, forwardings to the underlying red-black tree, std::less calls, etc. While determining purity and eliminating a richer set of common sub-expressions is conceptually possible, and might even be achievable in time better than O(n2) on program size, it's a tall order.
no subject
if (std::count_if(C.equal_range(key), value)>0) ...
Except that equal_range returns a std::pair of iterators and the <algorithm> functions and equivalent container methods only take individual iterators, so you have to at least calculate the range as a temporary.
if (C.count(C::value_type(key, value))>0) ...
Except that count() (or just find()!) are only defined on key_type, not value_type.
no subject
Given range support, especially if containers themselves presented the range concept, the algorithms that currently accept a pair of iterators would all accept a range and your std::count_if example would work out of the box.
Now that C++11 is out there, I'm seriously considering putting some concrete proposals in for the next revision of C++, including ranges.
no subject
no subject
I did consider using a transformed version of
value, e.g.value+1if it was an integer orvalue+"x"if a string, but in each of those cases I couldn't see any reason you'd do that – if you knew the type ofvalueanyway, it would be easier to just compare it against some constant thing not of that type.But it hadn't occurred to me that
not valuewould apply to all types. Cunning.no subject
But "not" is very good. Are there any weird edge cases? :)
no subject
no subject
>>> class foo: ... def __cmp__(self, other): ... if other is True: return 0 ... if other is False: return 0 ... return 1 ... >>> f = foo() >>> g = foo() >>> f == g False >>> d = {} >>> d[5] = f >>> d.get(6, not f) == f True >>> 6 in d and d[6] == f FalseNote cmp is -1,0,1 for less than/equal/greater than.
no subject
no subject
no subject
try:
if dictionary[key] == value:
# do stuff
else:
# do other stuff
except:
# do different stuff
?
no subject
If I was writing some complicated boolean expression along the lines ofand realised that the dictionary might not contain the key at all, then I'd much rather correct the code tothan have to turn it into something like this:
try: tmpvar = dict[key]==value except: tmpvar = False if a<b and c==d and (tmpvar or other_equally_good_case):There just doesn't seem to me to be any contest there.no subject
I don't think I've ever come across this in practice, though; normally, I just work with dicts which either don't contain None, or where None would be expected to be treated the same as the entry being missing.
no subject
except KeyError:" :p[sorry, "
except:" is one of my pet python hates]no subject
no subject
(key, value) in dictionary.viewitems()is horrific? It seems to me that it's pretty close to ideal. The only improvement would be if I'd been able to just write(key, value) in dictionary, on the principle that a dictionary is mathematically speaking a restricted form of relation and a relation is a subset of the set of possible ordered pairs. Sadly,in dictionarywas already used for something else.no subject
if dictionary.itemequals(key,value):
but that may just be my lack of familiary with Python showing. If the former code is idiomatic Python then go for it.
no subject
no subject
no subject
no subject
no subject
but as
no subject