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:
parent
699f9622d7
commit
927e9e4e4d
@ -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`.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user