热门角色不仅是灵感来源,更是你的效率助手。通过精挑细选的角色提示词,你可以快速生成高质量内容、提升创作灵感,并找到最契合你需求的解决方案。让创作更轻松,让价值更直接!
我们根据不同用户需求,持续更新角色库,让你总能找到合适的灵感入口。
本提示词根据用户输入生成完整函数,包括参数类型、功能逻辑、返回值及附加要求,支持附加约束与边界处理,帮助开发者快速创建健壮、高质量、可维护的代码。
def paginate_and_sort( data: "List[Dict[str, Any]]", sort_key: str, sort_order: "Literal['asc', 'desc']", page: int, page_size: int, missing_key_behavior: "Literal['skip', 'default']", default_value: "Any" = None, stable: bool = True, ) -> "Dict[str, Any]": """ 对记录列表进行稳健的排序与分页。
参数:
- data: List[Dict[str, Any]]
输入记录列表。函数对列表进行浅拷贝以保证输入不可变。
- sort_key: str
要排序的字段名。
- sort_order: 'asc' | 'desc'
排序方向:升序或降序。
- page: int
从1开始的页码。小于1将抛出ValueError。
- page_size: int
每页数量,范围建议为1~100。超出范围将抛出ValueError。
- missing_key_behavior: 'skip' | 'default'
当记录缺失sort_key或其值为None时的处理策略:
- 'skip': 直接排除该记录。
- 'default': 使用default_value填充值参与排序。
- default_value: Any
当策略为'default'时用于填充缺失的排序键值;不得为None,否则抛出ValueError。
- stable: bool
是否使用稳定排序以保持相同键值记录的原始相对顺序。True时保持稳定;False时对相同键值增加非稳定的确定性Tie-break(按对象id)以打乱原始顺序。
排序规则:
- 使用Python内置稳定排序(sorted)。
- 比较键归一化:
* 数值类型(int, float, Decimal, 以及bool)归为一类,支持NaN安全排序。
* 字符串归为一类。
* 其他类型使用字符串化回退(str(value),失败则repr(value)),确保不抛异常。
- 不同类型通过类型组排序,避免不可比较的混合类型导致异常。
分页:
- 计算 total_count 与 total_pages。
- 根据 page 与 page_size 截取当前页 items。
- 越界页返回空 items,但元数据正确。
返回:
Dict[str, Any],包含:
{
'total_count': int,
'total_pages': int,
'page': int,
'page_size': int,
'sort_key': str,
'sort_order': 'asc' | 'desc',
'items': List[Dict[str, Any]],
'has_prev': bool,
'has_next': bool
}
异常:
- ValueError: 参数非法(page<1、page_size不在[1, 100]、sort_order/策略非法、default策略但未提供有效default_value等)。
说明:
- 空列表输入时,直接返回空items与正确的分页元数据。
- 保持输入数据不可变(浅拷贝列表,不修改字典)。
- 大数据集仅进行一次稳定排序后分页切片,避免多次扫描。
"""
from typing import Any, Dict, List, Tuple
from decimal import Decimal
import math
# -------- 参数校验 --------
if not isinstance(page, int) or page < 1:
raise ValueError("page 必须为 >= 1 的整数。")
if not isinstance(page_size, int) or not (1 <= page_size <= 100):
raise ValueError("page_size 必须为 1~100 的整数。")
if sort_order not in ("asc", "desc"):
raise ValueError("sort_order 必须为 'asc' 或 'desc'。")
if missing_key_behavior not in ("skip", "default"):
raise ValueError("missing_key_behavior 必须为 'skip' 或 'default'。")
if not isinstance(sort_key, str) or not sort_key:
raise ValueError("sort_key 必须为非空字符串。")
if missing_key_behavior == "default" and default_value is None:
raise ValueError("当 missing_key_behavior='default' 时必须提供非 None 的 default_value。")
reverse = sort_order == "desc"
# -------- 归一化比较键 --------
def normalize_sort_value(value: Any) -> Tuple[int, int, Any]:
"""
返回用于排序的可比较键:(type_group, nan_flag, normalized_value)
type_group: 0=数值, 1=字符串, 2=其他(字符串化回退)
nan_flag: 0=非NaN, 1=NaN(仅数值类)
normalized_value: 实际比较值
"""
# 将 None 的处理在外层完成,这里不接收 None
# 数值(包含bool作为数值)
if isinstance(value, (int, float, Decimal, bool)):
# 将 Decimal 转为 float;bool/int 保留为int以稳定比较
if isinstance(value, Decimal):
v = float(value)
else:
v = float(value) if isinstance(value, float) else int(value)
is_nan = 1 if isinstance(v, float) and math.isnan(v) else 0
# 对NaN:通过nan_flag置后/置前,normalized_value可设为0占位
return (0, is_nan, 0 if is_nan else v)
# 字符串
if isinstance(value, str):
return (1, 0, value)
# 其他类型:字符串化回退
try:
s = str(value)
except Exception:
s = repr(value)
return (2, 0, s)
# -------- 浅复制以保持输入不可变 --------
records: List[Dict[str, Any]] = list(data or [])
# -------- 构建装饰列表(一次扫描) --------
decorated: List[Tuple[Tuple[int, int, Any], int, Dict[str, Any]]] = []
for rec in records:
raw_val = rec.get(sort_key, None)
if raw_val is None:
if missing_key_behavior == "skip":
continue
else:
# default
raw_val = default_value
norm_key = normalize_sort_value(raw_val)
# 稳定:使用sorted固有稳定性(不添加原始索引为tie-break)
# 非稳定:在相同norm_key下使用对象id打乱原始相对顺序(但结果仍然确定)
tie_break = 0 if stable else id(rec)
decorated.append((norm_key, tie_break, rec))
# -------- 排序(一次稳定排序) --------
# 当 stable=True 时,排序键仅为 norm_key;相同键的相对顺序由内置稳定排序保持。
# 当 stable=False 时,加入 tie_break(对象id)作为次级键以打乱相同键的原始顺序。
if stable:
sorted_decorated = sorted(decorated, key=lambda t: t[0], reverse=reverse)
else:
sorted_decorated = sorted(decorated, key=lambda t: (t[0], t[1]), reverse=reverse)
# -------- 分页 --------
total_count = len(sorted_decorated)
if total_count == 0:
total_pages = 0
items: List[Dict[str, Any]] = []
else:
total_pages = (total_count + page_size - 1) // page_size
start = (page - 1) * page_size
end = min(start + page_size, total_count)
if start >= total_count:
items = []
else:
# 单次切片,无额外扫描
items = [t[2] for t in sorted_decorated[start:end]]
has_prev = page > 1 and total_pages > 0
has_next = page < total_pages
return {
"total_count": total_count,
"total_pages": total_pages,
"page": page,
"page_size": page_size,
"sort_key": sort_key,
"sort_order": sort_order,
"items": items,
"has_prev": has_prev,
"has_next": has_next,
}
/**
/**
/**
/**
A combined token-bucket (rate limit) + semaphore (concurrency) implementation.
Multiple calls can share an instance to achieve global throttling. / class TokenBucket { /*
// Rate budget this.tokens = capacity; this.lastRefillMs = nowMs();
// Concurrency permits this.permits = capacity;
// Waiters queue this._waiters = []; // FIFO of { resolve, reject, minTimeMs, signal, onAbort } this._timerId = null; this._scheduledAtMs = 0; }
_refill() { const n = nowMs(); const elapsedMs = n - this.lastRefillMs; if (elapsedMs <= 0) return; const add = (elapsedMs / 1000) * this.refillPerSec; this.tokens = Math.min(this.capacity, this.tokens + add); this.lastRefillMs = n; }
_timeUntilOneTokenMs() { // Assuming _refill has been called if (this.tokens >= 1) return 0; const deficit = 1 - this.tokens; // positive return (deficit / this.refillPerSec) * 1000; }
_processQueue() { this._refill(); const now = nowMs();
// Fulfill as many as possible (must satisfy both rate token and permit)
let progressed = false;
while (this.tokens >= 1 && this.permits >= 1) {
// Find the first waiter whose minTimeMs <= now
let idx = -1;
for (let i = 0; i < this._waiters.length; i++) {
const w = this._waiters[i];
if (!w.signal || !w.signal.aborted) {
if (w.minTimeMs <= now) {
idx = i;
break;
}
} else {
// Clean aborted waiter
if (w.onAbort) w.signal.removeEventListener('abort', w.onAbort);
this._waiters.splice(i, 1);
i--;
}
}
if (idx === -1) break;
const waiter = this._waiters.splice(idx, 1)[0];
if (waiter.onAbort) waiter.signal.removeEventListener('abort', waiter.onAbort);
// Grant
this.tokens -= 1;
this.permits -= 1;
progressed = true;
waiter.resolve(() => {
// release permit only; tokens remain consumed (rate limit)
this.permits = Math.min(this.capacity, this.permits + 1);
// Try to fulfill more waiters that may now get concurrency
this._processQueue();
});
}
// Reschedule if there are pending waiters
if (this._waiters.length > 0) {
// Next time when a token is expected to be available for the earliest waiter.
// If permits are zero, we cannot know when a permit will be available; we rely on release() to trigger processing.
const soonestWaiterTime = this._waiters.reduce((min, w) => Math.min(min, w.minTimeMs), Infinity);
const waitMs = Math.max(0, soonestWaiterTime - now);
// If tokens insufficient and we have waiters blocked on tokens, schedule a timer
// Only schedule if waitMs is finite
if (Number.isFinite(waitMs)) {
// Avoid setting redundant timers if we already scheduled sooner
const fireAt = now + waitMs;
if (this._timerId != null) {
if (this._scheduledAtMs <= fireAt) {
// existing timer fires earlier or same time, keep it
return;
}
clearTimeout(this._timerId);
this._timerId = null;
}
this._scheduledAtMs = fireAt;
this._timerId = setTimeout(() => {
this._timerId = null;
this._scheduledAtMs = 0;
this._processQueue();
}, waitMs);
}
} else {
// No waiters; cancel any timer
if (this._timerId != null) {
clearTimeout(this._timerId);
this._timerId = null;
this._scheduledAtMs = 0;
}
}
}
/**
// Global shared buckets keyed by config const _sharedBuckets = new Map(); /**
${rateLimit.bucketSize}:${rateLimit.refillPerSec};
let b = _sharedBuckets.get(key);
if (!b) {
b = new TokenBucket(rateLimit.bucketSize, rateLimit.refillPerSec);
_sharedBuckets.set(key, b);
}
return b;
}/**
/**
/**
const bucket = getBucket(rateLimit); const startMs = nowMs(); let lastDelayMs = 0; let attempts = 0; const errors = [];
// Helper to create a timeout promise const makeTimeoutPromise = () => new Promise((_, reject) => { const id = setTimeout(() => reject(new TimeoutError()), timeoutMs); // Return handle to clear makeTimeoutPromise._id = id; });
for (let attemptIndex = 0; attemptIndex <= retries; attemptIndex++) { // Before each attempt, honor external abort if (signal && signal.aborted) { throw new AbortError(); }
// Acquire rate token + concurrency permit
let release;
try {
release = await bucket.acquire(signal);
} catch (e) {
// Acquire can reject with AbortError
throw e;
}
attempts++;
// Create abort and timeout races
const timeoutPromise = makeTimeoutPromise();
const timeoutId = makeTimeoutPromise._id;
const abortPromise = new Promise((_, reject) => {
if (signal) {
if (signal.aborted) {
reject(new AbortError());
return;
}
signal.addEventListener('abort', () => reject(new AbortError()), { once: true });
}
});
try {
const result = await Promise.race(
signal ? [fn(), timeoutPromise, abortPromise] : [fn(), timeoutPromise]
);
// Success
clearTimeout(timeoutId);
release();
const durationMs = nowMs() - startMs;
return {
value: result,
attempts,
lastDelayMs,
durationMs,
};
} catch (err) {
clearTimeout(timeoutId);
// Always release permit on failure/timeout/abort
release();
// Abort: terminate immediately
if (err instanceof AbortError) {
throw err;
}
// Record failure
errors.push({ error: err, attempt: attemptIndex + 1 });
// Exhausted?
if (attemptIndex >= retries) {
const agg = new AggregateError(
errors.map(e => e.error),
`All ${attempts} attempts failed`
);
// Attach attempt indices for diagnostics
agg.attempts = errors.map(e => e.attempt);
throw agg;
}
// Compute backoff delay
const base = baseDelayMs * Math.pow(2, attemptIndex);
const delayMs = jitter === 'full' ? Math.floor(Math.random() * base) : base;
lastDelayMs = delayMs;
if (typeof onRetry === 'function') {
try {
// attempt is 1-based count of the attempt that just failed
onRetry(err, attemptIndex + 1, delayMs);
} catch { /* ignore onRetry errors */ }
}
// Sleep before next attempt, respecting abort
await sleep(delayMs, signal);
}
}
// Should never reach here throw new Error('Unexpected control flow in retryWithRateLimit'); }
// Export for Node/CommonJS if needed // module.exports = { retryWithRateLimit, TokenBucket, TimeoutError, AbortError };
下面给出一个完整可用的 Java 实现,包含核心函数 mergeConfigWithSchema、模式结构 SchemaField、返回结果结构 MergeResult,以及必要的工具与安全校验逻辑。代码遵从不可变与线程安全原则,不修改输入 Map;对对象与数组进行深度合并与类型校验/转换;收集应用默认、类型转换与回退的诊断信息;并提供循环引用与最大深度防护。
代码说明要点:
可直接复制到工程中使用。
/**
public final class ConfigMerger {
private static final int MAX_PATH_DEPTH = 64;
private static final int MAX_MERGE_DEPTH = 256;
public enum Type {
STRING, NUMBER, BOOLEAN, OBJECT, ARRAY
}
public enum MergeStrategy {
REPLACE, CONCAT
}
/**
* Schema 字段定义。
*/
public static final class SchemaField {
private final String name; // 点号路径,例如 "db.pool.size"
private final Type type; // 期望类型
private final boolean required; // 是否必需
private final Object defaultValue; // 默认值,可为 null 表示未提供
private final List<Object> enumValues; // 枚举约束,可为 null
private final MergeStrategy mergeStrategy; // 数组合并策略
private final boolean coerce; // 是否允许类型转换
private final Predicate<Object> validate; // 自定义校验函数,可为 null
private SchemaField(Builder builder) {
this.name = Objects.requireNonNull(builder.name, "SchemaField.name");
this.type = Objects.requireNonNull(builder.type, "SchemaField.type");
this.required = builder.required;
this.defaultValue = builder.defaultValue;
this.enumValues = builder.enumValues == null ? null : new ArrayList<>(builder.enumValues);
this.mergeStrategy = builder.mergeStrategy == null ? MergeStrategy.REPLACE : builder.mergeStrategy;
this.coerce = builder.coerce;
this.validate = builder.validate;
}
public String getName() { return name; }
public Type getType() { return type; }
public boolean isRequired() { return required; }
public Object getDefaultValue() { return defaultValue; }
public List<Object> getEnumValues() { return enumValues; }
public MergeStrategy getMergeStrategy() { return mergeStrategy; }
public boolean isCoerce() { return coerce; }
public Predicate<Object> getValidate() { return validate; }
public static Builder builder() { return new Builder(); }
public static final class Builder {
private String name;
private Type type;
private boolean required;
private Object defaultValue;
private List<Object> enumValues;
private MergeStrategy mergeStrategy;
private boolean coerce;
private Predicate<Object> validate;
public Builder name(String name) { this.name = name; return this; }
public Builder type(Type type) { this.type = type; return this; }
public Builder required(boolean required) { this.required = required; return this; }
public Builder defaultValue(Object defaultValue) { this.defaultValue = defaultValue; return this; }
public Builder enumValues(List<Object> enumValues) { this.enumValues = enumValues; return this; }
public Builder mergeStrategy(MergeStrategy mergeStrategy) { this.mergeStrategy = mergeStrategy; return this; }
public Builder coerce(boolean coerce) { this.coerce = coerce; return this; }
public Builder validate(Predicate<Object> validate) { this.validate = validate; return this; }
public SchemaField build() { return new SchemaField(this); }
}
}
/**
* 合并结果。
*/
public static final class MergeResult {
private final Map<String, Object> config; // 不可变视图(深度)
private final List<String> warnings; // 警告信息
private final Map<String, Object> appliedDefaults; // 应用默认值映射(路径->默认)
private final List<String> coercedFields; // 完成类型转换的字段路径列表
public MergeResult(Map<String, Object> config,
List<String> warnings,
Map<String, Object> appliedDefaults,
List<String> coercedFields) {
this.config = config;
this.warnings = warnings;
this.appliedDefaults = appliedDefaults;
this.coercedFields = coercedFields;
}
public Map<String, Object> getConfig() { return config; }
public List<String> getWarnings() { return warnings; }
public Map<String, Object> getAppliedDefaults() { return appliedDefaults; }
public List<String> getCoercedFields() { return coercedFields; }
}
/**
* 主函数:按给定 schema 安全合并 baseConfig 与 userConfig。
*
* 合并规则:
* 1) 优先取 userConfig 值,其次 baseConfig;缺失且有 default 时应用默认。
* 2) 类型校验与可选类型转换(coerce):数字、布尔、JSON对象/数组;失败记录警告,仍保留原值或默认以保证可用性。
* 3) 深度合并:对象字段递归合并(user 覆盖 base);数组根据 mergeStrategy 替换或拼接(concat 保留顺序)。
* 4) 枚举与自定义校验:不通过回退默认并记录警告;无默认则保留当前值并记录警告。
* 5) 结果不可变:返回新的 Map 且深度不可变;收集诊断信息。
* 6) 防护:最大深度与循环引用检测。
*
* 注意:仅处理 schema 中定义的字段;未在 schema 定义的字段不会出现在结果中。
*/
public static MergeResult mergeConfigWithSchema(Map<String, Object> baseConfig,
Map<String, Object> userConfig,
List<SchemaField> schema) {
Map<String, Object> base = baseConfig == null ? Collections.emptyMap() : baseConfig;
Map<String, Object> user = userConfig == null ? Collections.emptyMap() : userConfig;
List<SchemaField> sch = schema == null ? Collections.emptyList() : schema;
Map<String, Object> resultRoot = new LinkedHashMap<>();
List<String> warnings = new ArrayList<>();
Map<String, Object> appliedDefaults = new LinkedHashMap<>();
List<String> coercedFields = new ArrayList<>();
for (SchemaField field : sch) {
String path = field.getName();
if (path == null || path.trim().isEmpty()) {
warnings.add("Schema field has empty path; skipped.");
continue;
}
List<String> parts = splitPath(path);
if (parts.size() > MAX_PATH_DEPTH) {
warnings.add("Path depth exceeds limit (" + MAX_PATH_DEPTH + "): " + path);
continue;
}
// 从 user 优先,再从 base;同时保留对象/数组的双源以便深度合并
Object userVal = getValueByPath(user, parts, path);
Object baseVal = getValueByPath(base, parts, path);
Object finalVal;
// 对象字段:进行深度合并
if (field.getType() == Type.OBJECT) {
Map<String, Object> oUser = toMapOrNull(userVal);
Map<String, Object> oBase = toMapOrNull(baseVal);
// 当缺失且有默认:默认可为 Map(优先作为初始 base)
Map<String, Object> oDefault = toMapOrNull(field.getDefaultValue());
Map<String, Object> merged;
IdentityHashMap<Object, Boolean> visited = new IdentityHashMap<>();
if (oUser == null && oBase == null && oDefault == null) {
if (field.isRequired()) {
warnings.add("Required object field missing and no default: " + path);
}
merged = new LinkedHashMap<>();
} else {
Map<String, Object> baseForMerge = oBase != null ? oBase : (oDefault != null ? oDefault : new LinkedHashMap<>());
merged = deepMergeMaps(baseForMerge, oUser, 0, visited, warnings, path);
if (oUser == null && oBase == null && oDefault != null) {
appliedDefaults.put(path, deepCopyValue(oDefault, new IdentityHashMap<>(), 0, warnings, path));
}
}
// 枚举/校验针对整个对象(一般不常用);若失败,回退默认或保留并警告
if (!checkEnum(field, merged)) {
if (oDefault != null) {
merged = deepCopyValue(oDefault, new IdentityHashMap<>(), 0, warnings, pathMap(path));
warnings.add("Enum constraint failed on object; applied default for: " + path);
appliedDefaults.put(path, deepCopyValue(oDefault, new IdentityHashMap<>(), 0, warnings, path));
} else {
warnings.add("Enum constraint failed on object and no default; kept value for: " + path);
}
}
if (field.getValidate() != null && !safeValidate(field.getValidate(), merged)) {
if (oDefault != null) {
merged = deepCopyValue(oDefault, new IdentityHashMap<>(), 0, warnings, pathMap(path));
warnings.add("Custom validation failed on object; applied default for: " + path);
appliedDefaults.put(path, deepCopyValue(oDefault, new IdentityHashMap<>(), 0, warnings, path));
} else {
warnings.add("Custom validation failed on object and no default; kept value for: " + path);
}
}
finalVal = merged;
} else if (field.getType() == Type.ARRAY) {
// 数组字段:按策略合并
List<Object> aUser = toListOrNull(userVal, field, warnings, coercedFields, path);
List<Object> aBase = toListOrNull(baseVal, field, warnings, coercedFields, path);
List<Object> aDefault = toListOrNull(field.getDefaultValue(), field, warnings, coercedFields, path);
List<Object> merged;
if (field.getMergeStrategy() == MergeStrategy.CONCAT) {
merged = new ArrayList<>();
if (aBase != null) merged.addAll(deepCopyList(aBase, warnings, path));
if (aUser != null) merged.addAll(deepCopyList(aUser, warnings, path));
if (aBase == null && aUser == null) {
if (aDefault != null) {
merged.addAll(deepCopyList(aDefault, warnings, path));
appliedDefaults.put(path, deepCopyList(aDefault, warnings, path));
} else {
merged = new ArrayList<>();
if (field.isRequired()) {
warnings.add("Required array field missing and no default: " + path);
}
}
}
} else {
// REPLACE
if (aUser != null) {
merged = deepCopyList(aUser, warnings, path);
} else if (aBase != null) {
merged = deepCopyList(aBase, warnings, path);
} else if (aDefault != null) {
merged = deepCopyList(aDefault, warnings, path);
appliedDefaults.put(path, deepCopyList(aDefault, warnings, path));
} else {
merged = new ArrayList<>();
if (field.isRequired()) {
warnings.add("Required array field missing and no default: " + path);
}
}
}
// 枚举:针对数组元素,所有元素必须在 enum 中
if (!checkEnumForArray(field, merged)) {
if (aDefault != null) {
merged = deepCopyList(aDefault, warnings, path);
warnings.add("Enum constraint failed on array; applied default for: " + path);
appliedDefaults.put(path, deepCopyList(aDefault, warnings, path));
} else {
warnings.add("Enum constraint failed on array and no default; kept value for: " + path);
}
}
// 自定义校验
if (field.getValidate() != null && !safeValidate(field.getValidate(), merged)) {
if (aDefault != null) {
merged = deepCopyList(aDefault, warnings, path);
warnings.add("Custom validation failed on array; applied default for: " + path);
appliedDefaults.put(path, deepCopyList(aDefault, warnings, path));
} else {
warnings.add("Custom validation failed on array and no default; kept value for: " + path);
}
}
finalVal = merged;
} else {
// 标量类型:取 user/base/default,然后进行类型校验与可选转换
Object candidate = userVal != null ? userVal : baseVal;
boolean appliedDefaultNow = false;
if (candidate == null) {
if (field.getDefaultValue() != null) {
candidate = field.getDefaultValue();
appliedDefault.putSafe(appliedDefaults, path, field.getDefaultValue());
appliedDefaultNow = true;
} else if (field.isRequired()) {
warnings.add("Required field missing and no default: " + path);
}
}
Object normalized = normalizeScalar(candidate, field, warnings, coercedFields, path);
// 枚举
if (!checkEnum(field, normalized)) {
if (field.getDefaultValue() != null) {
normalized = field.getDefaultValue();
if (!appliedDefaultNow) {
appliedDefault.putSafe(appliedDefaults, path, field.getDefaultValue());
}
warnings.add("Enum constraint failed; applied default for: " + path);
} else {
warnings.add("Enum constraint failed and no default; kept value for: " + path);
}
}
// 自定义校验
if (field.getValidate() != null && !safeValidate(field.getValidate(), normalized)) {
if (field.getDefaultValue() != null) {
normalized = field.getDefaultValue();
if (!appliedDefaultNow) {
appliedDefault.putSafe(appliedDefaults, path, field.getDefaultValue());
}
warnings.add("Custom validation failed; applied default for: " + path);
} else {
warnings.add("Custom validation failed and no default; kept value for: " + path);
}
}
finalVal = normalized;
}
// 写入结果,创建必要层级
putValueByPath(resultRoot, parts, deepCopyValue(finalVal, new IdentityHashMap<>(), 0, warnings, path));
}
// 返回深度不可变视图
Map<String, Object> immutable = asUnmodifiableDeep(resultRoot, new IdentityHashMap<>(), 0);
return new MergeResult(immutable,
Collections.unmodifiableList(new ArrayList<>(warnings)),
Collections.unmodifiableMap(new LinkedHashMap<>(appliedDefaults)),
Collections.unmodifiableList(new ArrayList<>(coercedFields)));
}
// ----------------- 工具与内部实现 -----------------
private static List<String> splitPath(String path) {
String[] arr = path.split("\\.");
List<String> parts = new ArrayList<>(arr.length);
for (String p : arr) {
if (!p.isEmpty()) parts.add(p);
}
return parts;
}
/**
* 从 Map 按路径取值。支持两种形式:
* - 嵌套对象:db -> pool -> size
* - 扁平键:直接存在 "db.pool.size"
*/
@SuppressWarnings("unchecked")
private static Object getValueByPath(Map<String, Object> root, List<String> parts, String fullPathKey) {
if (root == null) return null;
if (root.containsKey(fullPathKey)) {
return root.get(fullPathKey);
}
Map<String, Object> cur = root;
for (int i = 0; i < parts.size(); i++) {
Object v = cur.get(parts.get(i));
if (v == null) return null;
if (i == parts.size() - 1) return v;
if (!(v instanceof Map)) return null;
cur = (Map<String, Object>) v;
}
return null;
}
@SuppressWarnings("unchecked")
private static void putValueByPath(Map<String, Object> root, List<String> parts, Object value) {
Map<String, Object> cur = root;
for (int i = 0; i < parts.size() - 1; i++) {
String p = parts.get(i);
Object existing = cur.get(p);
Map<String, Object> next;
if (existing instanceof Map) {
next = (Map<String, Object>) existing;
} else {
next = new LinkedHashMap<>();
cur.put(p, next);
}
cur = next;
}
cur.put(parts.get(parts.size() - 1), value);
}
@SuppressWarnings("unchecked")
private static Map<String, Object> toMapOrNull(Object v) {
return (v instanceof Map) ? (Map<String, Object>) v : null;
}
@SuppressWarnings("unchecked")
private static List<Object> toListOrNull(Object v, SchemaField field,
List<String> warnings,
List<String> coercedFields,
String path) {
if (v instanceof List) {
return (List<Object>) v;
}
if (v instanceof String && field.isCoerce()) {
String s = (String) v;
Optional<Object> parsed = tryParseJson(s);
if (parsed.isPresent() && parsed.get() instanceof List) {
coercedFields.add(path);
return (List<Object>) parsed.get();
} else {
warnings.add("Failed to coerce string to array (JSON parse missing or invalid): " + path);
}
}
return null;
}
private static boolean checkEnum(SchemaField field, Object value) {
List<Object> enums = field.getEnumValues();
if (enums == null || enums.isEmpty()) return true;
// 若为数组类型,在专用方法中处理;此处针对非数组类型
if (field.getType() == Type.ARRAY) return true;
for (Object e : enums) {
if (Objects.equals(e, value)) return true;
}
return false;
}
private static boolean checkEnumForArray(SchemaField field, List<Object> arr) {
if (field.getType() != Type.ARRAY) return true;
List<Object> enums = field.getEnumValues();
if (enums == null || enums.isEmpty()) return true;
if (arr == null) return true;
for (Object v : arr) {
boolean ok = false;
for (Object e : enums) {
if (Objects.equals(e, v)) {
ok = true; break;
}
}
if (!ok) return false;
}
return true;
}
private static boolean safeValidate(Predicate<Object> validate, Object value) {
try {
return validate.test(value);
} catch (Exception e) {
return false;
}
}
private static Object normalizeScalar(Object candidate,
SchemaField field,
List<String> warnings,
List<String> coercedFields,
String path) {
if (candidate == null) return null;
switch (field.getType()) {
case STRING:
if (candidate instanceof String) return candidate;
if (field.isCoerce()) {
coercedFields.add(path);
return String.valueOf(candidate);
} else {
warnings.add("Type mismatch (expected string) for: " + path);
return candidate;
}
case NUMBER:
if (candidate instanceof Number) return candidate;
if (candidate instanceof String && field.isCoerce()) {
String s = ((String) candidate).trim();
try {
Object num = parseNumber(s);
coercedFields.add(path);
return num;
} catch (NumberFormatException ex) {
warnings.add("Failed to coerce string to number for: " + path);
return candidate;
}
} else {
warnings.add("Type mismatch (expected number) for: " + path);
return candidate;
}
case BOOLEAN:
if (candidate instanceof Boolean) return candidate;
if (field.isCoerce()) {
Boolean b = coerceToBoolean(candidate);
if (b != null) {
coercedFields.add(path);
return b;
} else {
warnings.add("Failed to coerce to boolean for: " + path);
return candidate;
}
} else {
warnings.add("Type mismatch (expected boolean) for: " + path);
return candidate;
}
case OBJECT:
if (candidate instanceof Map) return candidate;
if (candidate instanceof String && field.isCoerce()) {
Optional<Object> parsed = tryParseJson((String) candidate);
if (parsed.isPresent() && parsed.get() instanceof Map) {
coercedFields.add(path);
return parsed.get();
} else {
warnings.add("Failed to coerce string to object (JSON parse missing or invalid) for: " + path);
return candidate;
}
} else {
warnings.add("Type mismatch (expected object) for: " + path);
return candidate;
}
case ARRAY:
if (candidate instanceof List) return candidate;
if (candidate instanceof String && field.isCoerce()) {
Optional<Object> parsed = tryParseJson((String) candidate);
if (parsed.isPresent() && parsed.get() instanceof List) {
coercedFields.add(path);
return parsed.get();
} else {
warnings.add("Failed to coerce string to array (JSON parse missing or invalid) for: " + path);
return candidate;
}
} else {
warnings.add("Type mismatch (expected array) for: " + path);
return candidate;
}
default:
return candidate;
}
}
private static Object parseNumber(String s) {
if (s.matches("[-+]?\\d+")) {
return Long.parseLong(s);
} else if (s.matches("[-+]?\\d*\\.\\d+([eE][-+]?\\d+)?") || s.matches("[-+]?\\d+([eE][-+]?\\d+)?")) {
return Double.parseDouble(s);
}
throw new NumberFormatException("Invalid numeric string: " + s);
}
private static Boolean coerceToBoolean(Object v) {
if (v instanceof Boolean) return (Boolean) v;
if (v instanceof Number) {
int i = ((Number) v).intValue();
if (i == 0) return Boolean.FALSE;
if (i == 1) return Boolean.TRUE;
}
if (v instanceof String) {
String s = ((String) v).trim().toLowerCase(Locale.ROOT);
switch (s) {
case "true": case "1": case "yes": case "on": return Boolean.TRUE;
case "false": case "0": case "no": case "off": return Boolean.FALSE;
default: return null;
}
}
return null;
}
@SuppressWarnings("unchecked")
private static Map<String, Object> deepMergeMaps(Map<String, Object> base,
Map<String, Object> user,
int depth,
IdentityHashMap<Object, Boolean> visited,
List<String> warnings,
String path) {
if (depth > MAX_MERGE_DEPTH) {
warnings.add("Exceeded max merge depth at: " + path);
return new LinkedHashMap<>();
}
Map<String, Object> result = new LinkedHashMap<>();
// copy base
if (base != null) {
for (Map.Entry<String, Object> e : base.entrySet()) {
Object copied = deepCopyValue(e.getValue(), visited, depth + 1, warnings, path + "." + e.getKey());
result.put(e.getKey(), copied);
}
}
// merge user
if (user != null) {
for (Map.Entry<String, Object> e : user.entrySet()) {
Object uVal = e.getValue();
Object bVal = result.get(e.getKey());
String childPath = path + "." + e.getKey();
if (uVal != null && bVal != null && uVal instanceof Map && bVal instanceof Map) {
Map<String, Object> mergedChild = deepMergeMaps((Map<String, Object>) bVal, (Map<String, Object>) uVal, depth + 1, visited, warnings, childPath);
result.put(e.getKey(), mergedChild);
} else {
Object copied = deepCopyValue(uVal, visited, depth + 1, warnings, childPath);
result.put(e.getKey(), copied);
}
}
}
return result;
}
@SuppressWarnings("unchecked")
private static Object deepCopyValue(Object v,
IdentityHashMap<Object, Boolean> visited,
int depth,
List<String> warnings,
String path) {
if (v == null) return null;
if (depth > MAX_MERGE_DEPTH) {
warnings.add("Exceeded max copy depth at: " + path);
return null;
}
if (visited.containsKey(v)) {
warnings.add("Detected cyclic reference while copying at: " + path);
return null;
}
if (v instanceof Map) {
visited.put(v, Boolean.TRUE);
Map<String, Object> src = (Map<String, Object>) v;
Map<String, Object> copy = new LinkedHashMap<>();
for (Map.Entry<String, Object> e : src.entrySet()) {
copy.put(e.getKey(), deepCopyValue(e.getValue(), visited, depth + 1, warnings, path + "." + e.getKey()));
}
visited.remove(v);
return copy;
} else if (v instanceof List) {
visited.put(v, Boolean.TRUE);
List<Object> src = (List<Object>) v;
List<Object> copy = new ArrayList<>(src.size());
for (int i = 0; i < src.size(); i++) {
copy.add(deepCopyValue(src.get(i), visited, depth + 1, warnings, path + "[" + i + "]"));
}
visited.remove(v);
return copy;
} else {
// immutable/simple
return v;
}
}
private static List<Object> deepCopyList(List<Object> src,
List<String> warnings,
String path) {
return (List<Object>) deepCopyValue(src, new IdentityHashMap<>(), 0, warnings, path);
}
@SuppressWarnings("unchecked")
private static Map<String, Object> asUnmodifiableDeep(Map<String, Object> v,
IdentityHashMap<Object, Boolean> visited,
int depth) {
if (v == null) return null;
if (visited.containsKey(v)) return Collections.unmodifiableMap(v); // already processed
visited.put(v, Boolean.TRUE);
Map<String, Object> copy = new LinkedHashMap<>();
for (Map.Entry<String, Object> e : v.entrySet()) {
Object val = e.getValue();
if (val instanceof Map) {
copy.put(e.getKey(), asUnmodifiableDeep((Map<String, Object>) val, visited, depth + 1));
} else if (val instanceof List) {
copy.put(e.getKey(), asUnmodifiableDeepList((List<Object>) val, visited, depth + 1));
} else {
copy.put(e.getKey(), val);
}
}
return Collections.unmodifiableMap(copy);
}
@SuppressWarnings("unchecked")
private static List<Object> asUnmodifiableDeepList(List<Object> v,
IdentityHashMap<Object, Boolean> visited,
int depth) {
if (v == null) return null;
if (visited.containsKey(v)) return Collections.unmodifiableList(v);
visited.put(v, Boolean.TRUE);
List<Object> copy = new ArrayList<>(v.size());
for (Object val : v) {
if (val instanceof Map) {
copy.add(asUnmodifiableDeep((Map<String, Object>) val, visited, depth + 1));
} else if (val instanceof List) {
copy.add(asUnmodifiableDeepList((List<Object>) val, visited, depth + 1));
} else {
copy.add(val);
}
}
return Collections.unmodifiableList(copy);
}
/**
* 尝试解析 JSON 字符串为 Object(Map 或 List)。如果环境未提供 Jackson,则返回 empty。
* 使用反射探测 com.fasterxml.jackson.databind.ObjectMapper 是否存在。
*/
@SuppressWarnings("unchecked")
private static Optional<Object> tryParseJson(String json) {
try {
Class<?> omClass = Class.forName("com.fasterxml.jackson.databind.ObjectMapper");
Object om = omClass.newInstance();
Object reader = omClass.getMethod("readValue", String.class, Class.class).invoke(om, json, Object.class);
return Optional.ofNullable(reader);
} catch (Throwable ignore) {
return Optional.empty();
}
}
// 小工具:避免重复 put 默认值时覆盖为不同对象引用
private static final class appliedDefault {
static void putSafe(Map<String, Object> map, String path, Object val) {
map.put(path, val);
}
}
// 为 deepCopyValue 的 path 展开辅助
private static String pathMap(String path) { return path; }
// ----------------- JavaDoc 使用示例与测试建议 -----------------
/**
* 使用示例:
*
* Map<String, Object> base = new HashMap<>();
* base.put("db", new HashMap<String, Object>() {{
* put("pool", new HashMap<String, Object>() {{
* put("size", 5);
* }});
* }});
*
* Map<String, Object> user = new HashMap<>();
* user.put("db", new HashMap<String, Object>() {{
* put("pool", new HashMap<String, Object>() {{
* put("size", "10"); // 字符串将被转换为数字
* }});
* }});
*
* List<SchemaField> schema = Arrays.asList(
* SchemaField.builder()
* .name("db.pool.size")
* .type(Type.NUMBER)
* .required(true)
* .defaultValue(10)
* .coerce(true)
* .build(),
* SchemaField.builder()
* .name("feature.enabled")
* .type(Type.BOOLEAN)
* .required(false)
* .defaultValue(true)
* .coerce(true)
* .build(),
* SchemaField.builder()
* .name("tags")
* .type(Type.ARRAY)
* .mergeStrategy(MergeStrategy.CONCAT)
* .defaultValue(Arrays.asList("base"))
* .coerce(true)
* .build()
* );
*
* MergeResult result = ConfigMerger.mergeConfigWithSchema(base, user, schema);
* Map<String, Object> config = result.getConfig(); // 深度不可变
* List<String> warnings = result.getWarnings();
* Map<String, Object> appliedDefaults = result.getAppliedDefaults();
* List<String> coerced = result.getCoercedFields();
*
* 预期:
* - config["db"]["pool"]["size"] == 10(来自 user 的 "10" 字符串转换为数字 10)
* - appliedDefaults 在 "db.pool.size" 缺失且 default=10 时会包含 { "db.pool.size": 10 }
*/
/**
* 单元测试建议(示例场景):
* 1) 标量类型转换:
* - NUMBER: "42" -> 42;"3.14" -> 3.14;非法字符串 -> 警告且保留原值。
* - BOOLEAN: "true"/"false"/"1"/"0"/"yes"/"no" -> 转换;未知字符串 -> 警告且保留原值。
* 2) 对象深度合并:
* - base 中有 {a:{x:1}},user 中有 {a:{y:2}} -> 合并为 {a:{x:1,y:2}}。
* - 循环引用:Map 自引用时检测并停止,记录警告。
* 3) 数组合并:
* - REPLACE: user 覆盖 base;缺失使用 default。
* - CONCAT: base + user 保留顺序;两者缺失使用 default;无 default 返回空并警告若 required。
* 4) 枚举与校验:
* - enum=["INFO","WARN"],user="DEBUG" -> 回退 default 并记录警告;无 default 则保留并警告。
* - validate: 值必须为偶数,user=3 -> 回退 default 并警告;无 default 保留并警告。
* 5) 路径与默认:
* - "db.pool.size" 缺失且 default=10 -> appliedDefaults 包含 {"db.pool.size":10}。
* - required 字段缺失且无 default -> warnings 有对应告警;config 仍生成。
* 6) JSON 字符串:
* - ARRAY/OBJECT 字段在 coerce=true 时传入 JSON 字符串(需运行环境提供 Jackson),解析成功并记录 coercedFields;无 Jackson 或解析失败 -> 警告。
* 7) 不可变性:
* - 对返回的 Map/List 进行修改尝试(应抛出 UnsupportedOperationException)。
*/
}
帮助开发人员快速生成符合需求的带参数与逻辑说明的函数代码,节省开发时间,提高编程效率,让用户更专注于解决具体业务问题。
快速生成可靠的业务逻辑函数,减少基础代码编写时间,专注复杂功能开发。
通过提示词学习函数编写结构,快速提升代码逻辑与实践能力。
利用提示词将模糊需求转化为具体代码逻辑,提高跨部门沟通效率。
将模板生成的提示词复制粘贴到您常用的 Chat 应用(如 ChatGPT、Claude 等),即可直接对话使用,无需额外开发。适合个人快速体验和轻量使用场景。
把提示词模板转化为 API,您的程序可任意修改模板参数,通过接口直接调用,轻松实现自动化与批量处理。适合开发者集成与业务系统嵌入。
在 MCP client 中配置对应的 server 地址,让您的 AI 应用自动调用提示词模板。适合高级用户和团队协作,让提示词在不同 AI 工具间无缝衔接。
半价获取高级提示词-优惠即将到期