如何测试数组是否包含完整元素而非子集(yq/jq场景)
yq数组精确匹配的正确做法
问题根源
你碰到的contains返回true是因为yq(和jq)的contains逻辑是子集/包含匹配——对于数组来说,它会检查右侧数组的每个元素是否被左侧数组的元素包含(这里是字符串子串匹配,"pe"是"hyper"的子串,所以返回true),不是精确的元素匹配。
你的尝试是否正确?
你写的yq -n '["hyper"] as $i | $i - ["pe"] != $i'在判断数组是否存在目标元素这个场景下是有效的,但不够简洁,还存在边界问题:比如原数组是["pe"],目标是["pe", "pe"],这个写法会返回true,但实际上原数组并不包含两个"pe"元素,属于误判。
更可靠的解决方案
根据你的需求,分两种场景给出最优写法:
1. 检查数组是否包含某个精确元素
用in运算符直接判断,直观且准确:
# 判断"pe"是否在["hyper"]中,返回false yq -n '"pe" in ["hyper"]' # 判断"hyper"是否在["hyper"]中,返回true yq -n '"hyper" in ["hyper"]'
2. 判断两个数组是否完全相等(元素、顺序、数量都一致)
直接用==比较即可:
# 两个数组元素不同,返回false yq -n '["hyper"] == ["pe"]' # 两个数组完全相同,返回true yq -n '["hyper", "test"] == ["hyper", "test"]'
3. 进阶:判断数组是否包含目标数组的所有元素(数量匹配)
如果需要判断左侧数组是否包含右侧数组的所有元素(数量也要一致,比如["pe", "pe"]是否被["pe", "pe", "apple"]包含),可以用分组统计的方式:
yq -n '["pe", "pe"] as $target | ["pe", "pe", "apple"] as $arr | ($arr | group_by(.) | map({key: .[0], count: length})) as $arrCounts | ($target | group_by(.) | map({key: .[0], count: length})) as $targetCounts | all($targetCounts[]; .count <= ($arrCounts[] | select(.key == .key).count))'
内容的提问来源于stack exchange,提问作者Martin Mucha
相关产品推荐
相关产品推荐

