Nodes/comfy-ovum/_.intersection
ComfyUI Node

_.intersection

What's in every one of these lists?

By sfinktah·Created about a year ago·Updated 10 months ago· 7
_.intersection
  • py_list
  • arrays
  • LIST

_.intersection takes several lists and returns the values that show up in all of them. It's set theory as a node: "which tags are common to every workflow?" "Which seeds appear in every batch?" "Which model names exist in all three of these checkpoint lists?" If you've reached for Python's set_a & set_b, you know the operation - this makes it graph-native and keeps your lists as lists.

How it works

The port is honest about its strategy - it leans on sets, then falls back gracefully:

def intersection(self, *args):
    try:
        setobj = set(self.obj)
        for v in args:
            setobj = setobj & set(v)
        return self._wrap(list(setobj))
    except TypeError:
        result = _values(self.obj)
        for i, v in enumerate(args):
            for item in result:
                if item not in v:
                    result.remove(item)
        return self._wrap(result)

Fast path: convert everything to sets and intersect. If that throws a TypeError (something unhashable - a list, a dict - snuck in), it falls back to a membership-based scan that removes non-matches one by one. Either way you get back a list, not a set, so it stays ComfyUI-friendly.

The inputs that matter

  • py_list - the primary input (*), the first array. Also accepts a _.CHAIN to continue chaining.
  • arrays - an * input for the rest of the arrays. This is the one that trips people up: the tooltip says to provide multiple values as a JSON array, like [["a","b"],["b","c"]]. So the first list comes in on py_list, and every additional list nests inside one JSON value.

Output is a single LIST of the values present in every input list, with duplicates collapsed.

Where you'd actually use it

Anywhere you're comparing collections across sources. A practical one: you have several lists of allowed/denied values from different configs and you want the intersection - the tags that pass every filter. Or, inverted thinking: intersection gives you "safe in all contexts," which is a nice complement to _.union (everything, deduped) and _.difference (in the first but not the others). The three of them cover most list-comparison needs.

One thing to know: because it's set-based on the fast path, order isn't guaranteed and duplicates collapse. If you need to preserve original order or duplicates, this isn't the node.

Installing

Part of comfy-ovum (MIT). ComfyUI Manager → search comfy-ovum → install → restart, or:

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. (Pack-wide, requirements.txt pulls pymediainfo - system libmediainfo on Linux - plus tomli-w, requests, braceexpand, pillow, numpy, markdown-it-py, aiohttp.)

Gotchas

Two practical notes. First, remember the arrays input wants JSON - pasting ["b","c"] without the outer brackets feeds it one array, not a list of arrays, and you'll intersect with a string instead of a list. Second, the pack's README stamps the whole underscore family as WIP and not production-ready. For pure-data comparisons on modest lists, _.intersection behaves; just don't bet a nightly batch job on it.

Categoryovum/underscore

Inputs (2)

NameTypeDefaultDescription
py_listopt*Primary input object (expected array). You can still pass any JSON-serializable value. Also accepts _.CHAIN to continue chaining.
arraysopt*arrays: JSON allowed for arrays/objects where applicable. For multiple values, provide a JSON array (e.g., [1,2,3]).

Outputs (1)

NameTypeDescription
LISTLIST