You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

jq中使用滑动窗口处理数组是否有比索引法更优的实现方式?

问题说明

需要将形如["a", 1, "b", 2, "c", 3]的交替键值数组,转换为{"a": 1, "b": 2, "c": 3}格式的对象。这类需求的通用处理逻辑是滑动窗口(本场景窗口大小为2、步长为2)切分数组。
原有基于数组索引的实现写法繁琐,且需要将全量数组加载到内存,对流式处理支持不佳,原有代码如下:

# 生成测试用输入,本示例中为从'a'到'z'的所有字母
function input () {
  printf '"%s" ' {a..z} | jq --slurp --compact-output '.'
}

input | 
  jq '. as $i | $i 
    | keys 
    | map(select (. % 2 == 0)) 
    | map({key:($i[.]|tostring), value:$i[. + 1]}) 
    | from_entries'

预期的理想写法是实现类Scala集合的sliding(size: Int, step: Int)方法,直接调用滑动窗口逻辑简化代码:

input | 
  jq 'sliding(2;2) 
    | map({key: (.[0]|tostring), value: .[1]) 
    | from_entries'

实现方案

jq本身没有内置sliding方法,但可以通过内置的while迭代语法快速实现等价效果,写法和预期的理想形式几乎一致。

场景专属快速实现

针对当前窗口大小2、步长2的键值转换场景,可以直接写出如下简洁代码:

# 沿用前述测试输入生成函数
input | jq '
  [while(. != []; .[2:]) | .[:2]]
  | map({key: .[0]|tostring, value: .[1]})
  | from_entries
'

核心逻辑说明:

  • while(. != []; .[2:]) 会迭代生成每次向后滑动2个位置后的剩余数组,直到数组为空时停止迭代
  • 对每次迭代得到的剩余数组取前2位,即为单个大小为2的滑动窗口
  • 外层用[]将所有迭代生成的窗口收集为二维数组,后续直接按键值对转换逻辑生成对象即可

通用sliding函数封装

如果需要复用到其他窗口大小、步长的场景,可以将滑动逻辑封装为自定义jq函数,实现和预期完全一致的调用形式:

# 定义通用滑动窗口函数:sliding(窗口大小; 滑动步长)
def sliding(size; step):
  [while(. != []; .[step:]) | .[:size]];

# 调用示例,和理想写法完全匹配
input | jq '
  sliding(2;2)
  | map({key: .[0]|tostring, value: .[1]})
  | from_entries
'

该实现的优势:

  • 逻辑可读性高,传入的size参数会直接控制每个窗口的截取长度,中间输出结果清晰易读
  • 不需要提前遍历全量数组生成索引列表,处理逻辑更直观
  • 配合jq的--stream流式参数,可以支持超大数组的逐段处理,不需要将全量数据加载到内存
    如果需要验证不同窗口大小的效果,比如窗口大小3、步长2,直接调用sliding(3;2)即可得到对应切分结果,和测试的while(. != []; .[2:])[:3]输出完全一致。

内容的提问来源于stack exchange,提问作者Morgen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 16:06:30