1
0
mirror of https://github.com/janet-lang/janet synced 2025-07-06 20:12:53 +00:00

Make contains? consistently iterate over values.

Remove `contains-value?` because it is now redundant.

Clarify in the documentation that it checks dictionary values.
This commit is contained in:
Techcable 2022-08-26 14:22:27 -07:00
parent 699f9622d7
commit 927e9e4e4d
No known key found for this signature in database
GPG Key ID: D7B98ADFF827CD17

View File

@ -1200,60 +1200,23 @@
~(def ,alias :dyn ,;more ,kw)) ~(def ,alias :dyn ,;more ,kw))
(defn contains-value?
```Checks if a collection contains the specified value.
Semantically equivalent to `(contains? (values dict) val)`,
but implemented more efficiently.
Unlike contains-key?, this has worst-case O(n) performance.
Noe that tables or structs (dictionaries) never contain null keys```
[collection target-val]
# Avoid allocating intermediate array for dictionary
# This works for both dictionaries and sequences
(cond
(indexed? collection) (not (nil? (index-of target-val collection)))
(dictionary? collection)
(do
(var res false)
(var k (next collection nil))
(unless (or (nil? k) (nil? target-val))
(while true
(def val (in collection k))
(cond
# We found a result, this will break the loop
(= val target-val) (do
(set res true)
(break))
# Reached end of dictionary
(nil? k) (break))
(set k (next collection k))))
res)
false))
(defn contains-key? (defn contains-key?
```Checks if a collection contains the specified key. ```Checks if a collection contains the specified key.
Functions the same as contains? for dictionaries (table/structs). Semantically equivalent to `(not (nil? (get collection key)))`.
Arrays and tuples are indexed by integer keys, and this function simply
checks if the index is valid. Arrays, tuples, and buffer types (string/keyword) are indexed by integer keys.
For those types, this function simply checks if the index is valid.
If this function succeeds, then a call to `(in collection key)` is guarenteed If this function succeeds, then a call to `(in collection key)` is guarenteed
to succeed as well. to succeed as well.
For dictionaries, this should be (approximate) O(1) time due to the Note that tables or structs (dictionaries) never contain null keys```
guarentees of table/struct.
For arrays and tuples it should likewise be O(1) because it is simply a comparison.
Note that this intentionally excludes string (and buffer types), for the same reasons
as `contains?` does.
Noe that tables or structs (dictionaries) never contain null keys```
[collection key] [collection key]
(not (nil? (get collection key)))) (not (nil? (get collection key))))
(defn contains? (defn contains?
```Checks if a collection contains the specified value (or key). ```Checks if a collection, buffer, or any other iterable type contains the specified value.
For tables and structs, this only checks the keys, For tables and structs, this only checks the keys,
and not the values. and not the values.
@ -1261,18 +1224,23 @@
For arrays and tuples this takes O(n) time, For arrays and tuples this takes O(n) time,
while for tables and structs this takes (average) O(1) time. while for tables and structs this takes (average) O(1) time.
This intentionally throws an error when strings are encountered. Technically, Warning: For buffer types (strings, buffers, keywords), this checks if the specified byte is present.
strings are an iterable type, they will succeed with `next` and `index-of`. Technically, buffers and strings are an iterable type, they will also work with `next` and `index-of`.
Interpreting a string as an iterable type, one would expect this to check "contains byte".
However, the user would very probably expect "contains substring". If the type is not iterable, this will return false.
Therefore, we intentionally forbid strings (and other buffer types).
NOTE on strings: `(contains? str val) will only check for byte values of `val`, not substrings.
Note that dictionaries never contain null keys``` In other words is `(contains? "foo bar" foo") will return false (because "foo" is not an integer byte).
If you want to check for a substring in a buffer, then use `(not (nil? (string/find substr :foo)))`
In general this function has O(n) performance, since it requires iterating over all the values.
Note that tables or structs (dictionaries) never contain null values```
[collection val] [collection val]
(cond # NOTE: index-of throws excpetion if `collection` is not iterable
(indexed? collection) (not (nil? (index-of val collection))) #
(dictionary? collection) (not (nil? (get collection val))) # guard against that
false)) (try (not (nil? (index-of val collection))) false))
(defdyn *defdyn-prefix* ``Optional namespace prefix to add to keywords declared with `defdyn`. (defdyn *defdyn-prefix* ``Optional namespace prefix to add to keywords declared with `defdyn`.