_.indexBy
Turn a list of records into a dict you can look up by key
- list_or_dict
- iteratee
- DICT
_.indexBy takes a list of things and builds a dictionary keyed by something you choose. Think: "I have a list of image records, now let me look them up by filename without scanning the list." That's the whole pitch, and it's genuinely the most useful of the pack's dictionary-builders because the result is a lookup structure you can index into downstream.
How it works
It's Underscore.js's _.indexBy, which is _.groupBy's sibling for when you know your keys are unique. Given a collection and an iteratee, it runs each element through the iteratee to get a key, then stores that element under the key:
def indexBy(self, iteratee=None):
if iteratee is None:
iteratee = lambda *args: args[0]
def by(result, key, value):
result[key] = value
res = self._group(self.obj, iteratee, by)
return self._wrap(res)
If you give it no iteratee, it keys by the elements themselves (each element becomes its own key). Give it a property name and it keys by that property. Give it a function and it keys by whatever the function returns.
The inputs that matter
- list_or_dict - the primary input (
*). A list of records is the natural fit; it also accepts a_.CHAINto continue chaining. - iteratee - an
*input for a function, key string, or object shorthand that picks the key. Leave unconnected to fall back to the JSON editor below. - iteratee_json - a multiline
STRING. This is the one you'll actually type into. The tooltip says it's "JSON or key selector," used wheniterateeisn't connected. For the common case - "index by this property" - you just type the property name as a plain string, likefilenameorseed.
Output is a single DICT. Wire it into anything that takes a dictionary - the pack's New Multi-type Dictionary-style consumers, a _.get/_.pluck node, or a formatter that indexes {arg0[key]}.
Where you'd actually use it
The recipe that clicks: upstream you have a list of workflow records, image paths, or metadata dicts (say from a JSON loader or a list-builder). Feed it to _.indexBy with filename as the key selector, and you get a dict where filename → record. Now instead of filtering a list, you do a direct key lookup - O(1) instead of scanning. It also pairs with _.include or _.invert for reverse lookups.
One trap: _.indexBy assumes unique keys. If two elements produce the same key, the last one wins silently. That's why it's "for when you know your keys are unique" - use _.groupBy if you don't.
Installing
Ships in comfy-ovum (MIT). ComfyUI Manager → search comfy-ovum → install → restart, or clone:
cd ComfyUI/custom_nodes
git clone https://github.com/sfinktah/comfy-ovum
The underscore nodes run on the underscore3 port bundled in the repo - no extra install. The pack as a whole pulls pymediainfo, tomli-w, requests, braceexpand, pillow, numpy, markdown-it-py, aiohttp from its requirements.
Gotchas
The whole underscore family is author-labeled WIP ("an absolute disaster to use in production" is the README's own phrasing), so treat _.indexBy as an experiment, not a dependency. The iteratee story is also the fiddliest part of these nodes - functions are hard to express in a GUI, which is why you'll mostly use plain-string key selectors. Keep it to key strings and it behaves.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| list_or_dictopt | * | Primary input object (expected collection). You can still pass any JSON-serializable value. Also accepts _.CHAIN to continue chaining. | |
| iterateeopt | * | iteratee: ANY input to override widget. Accepts function, key string, or object shorthand. | |
| iteratee_jsonopt | STRING | iteratee_json: JSON or key selector. Used when 'iteratee' input is not connected. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| DICT | DICT | — |