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

使用jq的reduce函数转换数组为对象时保留重复key的解决方案

问题与解决方案

问题描述

我有一个经jq处理大JSON文件后得到的数组,格式如下:

[
  {
    "Action": {
      "name1": {
        "product": {
          "summary": "Summary Product"
        }
      }
    }
  },
  {
    "Action": {
      "name2": {
        "gproduct": {
          "summary": "Summary Product"
        }
      }
    }
  },
  {
    "Action": {
      "name3": {
        "product1": {
          "summary": "Summary Product1"
        }
      }
    }
  },
  {
    "Action": {
      "name3": {
        "product2": {
          "summary": "Summary Product2"
        }
      }
    }
  }
]

我期望将其转换为包含重复name3条目的对象:

{
  "Action": {
    "name1": {
      "product": {
        "summary": "Summary Product"
      }
    },
    "name2": {
      "gproduct": {
        "summary": "Summary Product"
      }
    },
    "name3": {
      "product1": {
        "summary": "Summary Product1"
      }
    },
    "name3": {
      "product2": {
        "summary": "Summary Product2"
      }
    }
  }
}

但使用jq命令:

reduce .[] as $o ({}; reduce ($o|keys)[] as $key (.; .[$key] += $o[$key] ))

得到的结果中name3仅保留了最后一个product:

{
  "Action": {
    "name1": {
      "product": {
        "summary": "Summary Product"
      }
    },
    "name2": {
      "gproduct": {
        "summary": "Summary Product"
      }
    },
    "name3": {
      "product2": {
        "summary": "Summary Product2"
      }
    }
  }
}

请问如何修改jq命令,才能让同名的nameX对应的所有product都被单独保留,而不被覆盖?


解决方案

首先需要明确:JSON规范不允许对象存在重复键,绝大多数JSON解析器遇到重复键时,只会保留最后一个键值对,所以你期望的格式在标准JSON中是不合法的,无法被正常解析。

标准合法的处理方式(推荐)

将同名的nameX对应的结构存入数组,调整后的目标结构如下:

{
  "Action": {
    "name1": [
      {
        "product": {
          "summary": "Summary Product"
        }
      }
    ],
    "name2": [
      {
        "gproduct": {
          "summary": "Summary Product"
        }
      }
    ],
    "name3": [
      {
        "product1": {
          "summary": "Summary Product1"
        }
      },
      {
        "product2": {
          "summary": "Summary Product2"
        }
      }
    ]
  }
}

对应的jq命令:

{ Action: reduce .[].Action as $a ({};
    reduce ($a | keys[]) as $k (.; .[$k] += [$a[$k]])
  )
}

命令逻辑说明:

  • 遍历原始数组的每个元素,提取其中的Action对象
  • 对每个Action内的键(如name1、name3),将对应的值以数组元素的形式追加到结果的对应键中
  • 最终同名的name会对应一个数组,包含所有相关的product结构

非标准的重复键输出(不推荐)

如果因特殊需求必须输出带有重复键的非标准JSON(兼容性极差,多数工具无法正确解析),可以用jq的字符串拼接方式实现:

jq -r '
  "{\"Action\": {" +
  (.[] | to_entries[] | .value | to_entries[] | "\"\(.key)\": \(tojson)") |
  join(", ") +
  "}}"'

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 05:05:26