206 lines
7.7 KiB
Python
206 lines
7.7 KiB
Python
class CrossJoinSelector:
|
|
# 使用全局字典存储所有实例的状态
|
|
state_dict = {}
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(s):
|
|
return {
|
|
"required": {
|
|
"separator": ("STRING", {"default": ","}),
|
|
"reset": ("BOOLEAN", {"default": False}),
|
|
"input_1": ("STRING", {"forceInput": True}),
|
|
"limit_1": ("INT", {"default": 0, "min": 0, "max": 999999}),
|
|
},
|
|
"optional": {
|
|
"input_2": ("STRING", {"forceInput": True}),
|
|
"limit_2": ("INT", {"default": 0, "min": 0, "max": 999999}),
|
|
"input_3": ("STRING", {"forceInput": True}),
|
|
"limit_3": ("INT", {"default": 0, "min": 0, "max": 999999}),
|
|
"input_4": ("STRING", {"forceInput": True}),
|
|
"limit_4": ("INT", {"default": 0, "min": 0, "max": 999999}),
|
|
"input_5": ("STRING", {"forceInput": True}),
|
|
"limit_5": ("INT", {"default": 0, "min": 0, "max": 999999}),
|
|
}
|
|
}
|
|
|
|
RETURN_TYPES = ("STRING", "STRING", "STRING", "STRING", "STRING")
|
|
RETURN_NAMES = ("output_1", "output_2", "output_3", "output_4", "output_5")
|
|
FUNCTION = "cross_join"
|
|
CATEGORY = "selector"
|
|
|
|
# 添加IS_CHANGED方法来禁用缓存
|
|
@classmethod
|
|
def IS_CHANGED(s, input_1, separator, reset, limit_1, input_2=None, limit_2=0,
|
|
input_3=None, limit_3=0, input_4=None, limit_4=0, input_5=None, limit_5=0):
|
|
import time
|
|
return time.time()
|
|
|
|
def _parse_inputs(self, input_1, separator, limit_1, input_2=None, limit_2=0,
|
|
input_3=None, limit_3=0, input_4=None, limit_4=0, input_5=None, limit_5=0):
|
|
"""解析输入并返回有效的输入列表和限制"""
|
|
inputs = []
|
|
limits = []
|
|
|
|
for inp, limit in [(input_1, limit_1), (input_2, limit_2),
|
|
(input_3, limit_3), (input_4, limit_4),
|
|
(input_5, limit_5)]:
|
|
if not inp or not inp.strip():
|
|
continue
|
|
|
|
items = [item.strip() for item in inp.split(separator) if item.strip()]
|
|
if not items:
|
|
continue
|
|
|
|
inputs.append(items)
|
|
limits.append(limit)
|
|
|
|
return inputs, limits
|
|
|
|
def _get_current_outputs(self, inputs, indices, max_lengths):
|
|
"""根据当前索引生成输出"""
|
|
outputs = [""] * 5
|
|
for i, (input_list, idx) in enumerate(zip(inputs, indices)):
|
|
outputs[i] = input_list[idx % max_lengths[i]]
|
|
return outputs
|
|
|
|
def _should_carry(self, level, indices, max_lengths, counts, limits):
|
|
"""判断是否需要进位
|
|
|
|
Args:
|
|
level: 当前层级
|
|
indices: 各层级的当前索引
|
|
max_lengths: 各层级的最大长度
|
|
counts: 各层级的当前计数
|
|
limits: 各层级的限制次数
|
|
|
|
Returns:
|
|
tuple: (need_carry, reset_current)
|
|
- need_carry: 是否需要进位到上一层
|
|
- reset_current: 是否需要重置当前层的索引
|
|
"""
|
|
if level < 0:
|
|
return False, False
|
|
|
|
limit = limits[level]
|
|
current_index = indices[level]
|
|
current_count = counts[level]
|
|
max_length = max_lengths[level]
|
|
|
|
# 如果有限制
|
|
if limit > 0:
|
|
if current_count >= limit:
|
|
# 达到限制次数,需要进位但不重置索引
|
|
return True, False
|
|
# 如果没有限制,检查是否超出长度
|
|
elif current_index >= max_length:
|
|
# 超出长度,需要进位且重置索引
|
|
return True, True
|
|
|
|
return False, False
|
|
|
|
def _update_indices(self, inputs, limits, indices, counts):
|
|
"""更新索引和计数
|
|
|
|
实现嵌套循环的进位逻辑:
|
|
1. 内层到达限制或遍历完时进位到外层
|
|
2. 根据情况重置内层的索引和计数
|
|
3. 外层索引加1,计数加1
|
|
|
|
Args:
|
|
inputs: 输入列表的列表
|
|
limits: 限制次数的列表
|
|
indices: 当前索引的列表
|
|
counts: 当前计数的列表
|
|
|
|
Returns:
|
|
tuple: (indices, counts) 更新后的索引和计数
|
|
"""
|
|
if not indices:
|
|
return indices, counts
|
|
|
|
max_lengths = [len(input_list) for input_list in inputs]
|
|
level = len(indices) - 1
|
|
|
|
# 更新最内层的索引和计数
|
|
indices[level] += 1
|
|
counts[level] += 1
|
|
|
|
# 从内到外处理进位
|
|
while level >= 0:
|
|
need_carry, reset_current = self._should_carry(
|
|
level, indices, max_lengths, counts, limits
|
|
)
|
|
|
|
if need_carry:
|
|
# 进位时总是重置计数,根据返回值决定是否重置索引
|
|
counts[level] = 0
|
|
if reset_current:
|
|
indices[level] = 0
|
|
|
|
# 进位到上一层
|
|
level -= 1
|
|
if level >= 0:
|
|
indices[level] += 1
|
|
counts[level] += 1
|
|
else:
|
|
# 不需要进位,确保当前索引和计数在有效范围内
|
|
indices[level] = indices[level] % max_lengths[level]
|
|
if limits[level] > 0:
|
|
counts[level] = counts[level] % limits[level]
|
|
break
|
|
|
|
return indices, counts
|
|
|
|
def _is_iteration_complete(self, indices, max_lengths, counts, limits):
|
|
"""检查是否所有层级都完成了遍历"""
|
|
for i, (idx, max_len, count, limit) in enumerate(zip(indices, max_lengths, counts, limits)):
|
|
if limit > 0:
|
|
if count < limit:
|
|
return False
|
|
else:
|
|
if idx < max_len:
|
|
return False
|
|
return True
|
|
|
|
def cross_join(self, input_1, separator, reset=False, limit_1=0,
|
|
input_2=None, limit_2=0, input_3=None, limit_3=0,
|
|
input_4=None, limit_4=0, input_5=None, limit_5=0):
|
|
# 解析输入
|
|
inputs, limits = self._parse_inputs(input_1, separator, limit_1, input_2, limit_2,
|
|
input_3, limit_3, input_4, limit_4, input_5, limit_5)
|
|
|
|
# 如果没有有效输入,返回空结果
|
|
if not inputs:
|
|
return ("", "", "", "", "")
|
|
|
|
# 生成状态键并获取或初始化状态
|
|
state_key = "|".join(f"{limit}:{','.join(input_list)}" for input_list, limit in zip(inputs, limits))
|
|
|
|
if reset or state_key not in self.__class__.state_dict:
|
|
self.__class__.state_dict[state_key] = {
|
|
"indices": [0] * len(inputs),
|
|
"counts": [0] * len(inputs)
|
|
}
|
|
|
|
# 获取当前状态
|
|
state = self.__class__.state_dict[state_key]
|
|
indices = state["indices"]
|
|
counts = state["counts"]
|
|
max_lengths = [len(input_list) for input_list in inputs]
|
|
|
|
# 获取当前输出
|
|
outputs = self._get_current_outputs(inputs, indices, max_lengths)
|
|
|
|
# 更新状态
|
|
indices, counts = self._update_indices(inputs, limits, indices, counts)
|
|
|
|
# 检查是否需要重置
|
|
if self._is_iteration_complete(indices, max_lengths, counts, limits):
|
|
indices = [0] * len(inputs)
|
|
counts = [0] * len(inputs)
|
|
|
|
# 保存状态
|
|
state["indices"] = indices
|
|
state["counts"] = counts
|
|
|
|
return tuple(outputs) |