_.indexOf
Find where a value sits in a list, without crashing when it's missing
- py_list
- value
- INT
_.indexOf returns the position of a value in a list - or -1 if the value isn't there. If you've ever had a Python ValueError kill a workflow because you called list.index() on a missing item, this is the version that doesn't do that. It never raises; you just get -1 and you branch on it.
It's the direct port of Underscore.js's _.indexOf, and it fills a small but real hole in vanilla ComfyUI, which has no built-in "give me the position of this thing in this list" node.
How it works
Under the hood it's a linear scan using == equality:
def indexOf(self, value, isSorted=False):
array = self.obj
ret = -1
if not (self._clean.isList() or self._clean.isTuple()):
return self._wrap(-1)
...
while i < l:
if array[i] == value:
...
If the input isn't a list or tuple, it returns -1 rather than throwing. That's the Underscore ethos - fail soft, hand the workflow a value it can branch on.
The isSorted flag is the interesting toggle. If your list is already sorted, you can set it to true and it uses a binary search via _.sortedIndex under the hood - much faster on big lists. Turn it on a list that isn't sorted, though, and the result is garbage; the flag is an assertion you're making about your data.
The inputs that matter
- py_list - the primary input (
*). Note the name: the generator guessed this is an array method, so the socket is calledpy_list. It also accepts a_.CHAINto continue chaining. - value - what you're locating. Typed
*, so strings, numbers, anything. - isSorted - a
BOOLEAN(default false). Set true to use the faster binary-search path on a sorted list.
Output is a single INT. That index can drive a _.initial/_.rest-style slice, a First/Last selector, or a comparison node ("is this at position 0?").
Where you'd actually use it
The natural workflow pattern is a cheap membership-position check: which seed is in this batch, which tag landed at what index, which checkpoint rank does the current model hold. Combined with _.include (which internally reuses indexOf-style logic) you get both "is it there" and "where."
Installing
Part of comfy-ovum (MIT). Easiest: ComfyUI Manager → search comfy-ovum → install → restart. Or:
cd ComfyUI/custom_nodes
git clone https://github.com/sfinktah/comfy-ovum
The underscore nodes need no extra dependencies - they run on the underscore3 port bundled in the repo. (The pack-wide requirements.txt does include pymediainfo, which on Linux wants the system libmediainfo library, but that's unrelated to this node.)
Gotchas
Two things to know. First, the README stamps the whole underscore family as WIP and not production-ready - fine for experiments, less fine as a load-bearing dependency. Second, the binary-search path in the port checks identity (array[i] is value) after positioning, which can be flaky with string interning or copied objects; if isSorted gives you weird -1s, drop back to the default linear scan. The linear path uses ==, which is the safe one.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| py_listopt | * | Primary input object (expected array). You can still pass any JSON-serializable value. Also accepts _.CHAIN to continue chaining. | |
| valueopt | * | value: JSON allowed for arrays/objects where applicable. | |
| isSortedopt | BOOLEAN | false | isSorted (boolean) |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| INT | INT | — |