【问题标题】:How to limit values (clamp) in JSON with JQ?如何使用 JQ 限制 JSON 中的值(钳位)?
【发布时间】:2019-07-05 18:01:18
【问题描述】:

我有一个应用程序将数据写入/连接到 JSON 中,然后通过 dygraphs 显示/绘制它。有时,各种事件会导致值超出范围。该范围是用户主观的,因此在运行时限制该范围不是我想要的方向。

我相信 jq 在这里可以提供帮助 - 理想情况下,我可以搜索 > x 的字段,如果它是 > x,则将其替换为 x。我已经去搜索 jq 示例,但还没有真正找到任何对我有意义的东西。

我在这方面花了一些时间,但无法让任何事情做我认为应该做的事情......根本。就像,我没有糟糕的代码给你看,因为我还没有让它做任何事情。我真诚地希望我所要求的范围缩小到足以让某人能够在上下文中向我展示,以便我可以将其扩展到更大的项目。

这是我希望能够修改的一行:

{"cols":[{"type":"datetime","id":"Time","label":"Time"},{"type":"number","id":"Room1Temp","label":"Room One Temp"},{"type":"number","id":"Room1Set","label":"Room One Set"},{"type":"string","id":"Annot1","label":"Room One Note"},{"type":"number","id":"Room2Temp","label":"Room Two Temp"},{"type":"number","id":"Room2Set","label":"Room Two Set"},{"type":"string","id":"Annot2","label":"Room Two Note"},{"type":"number","id":"Room3Temp","label":"Room Three Temp"},{"type":"number","id":"State","label":"State"},{"type":"number","id":"Room4Temp","label":"Room Four Temp"},{"type":"number","id":"Quality","label":"Quality"}],"rows":[
{"c":[{"v":"Date(2019,6,4,20,31,13)"},{"v":68.01},{"v":68.0},null,{"v":62.02},{"v":55.89},null,null,{"v":4},{"v":69.0},{"v":1.052}]}]}

我想做这样的事情:

if JSONFile.Room2Set < 62
    set Room2Set = 62

Here's a larger block of JSON是下图的来源:

Example Chart

【问题讨论】:

    标签: python json jq


    【解决方案1】:

    使用这样定义的函数clamp 函数(在您的 ~/.jq 文件中或内联):

    def clamp_min($minInc): if . < $minInc then $minInc else . end;
    def clamp_max($maxInc): if . > $maxInc then $maxInc else . end;
    def clamp($minInc; $maxInc): clamp_min($minInc) | clamp_max($maxInc);
    

    使用这些数据,您需要找到每一行对应的单元格并修改值。

    $ jq --arg col "Room2Set" --argjson max '62' '
    def clamp_max($maxInc): if . > $maxInc then $maxInc else . end;
    (INDEX(.cols|to_entries[]|{id:.value.id,index:.key};.id)) as $cols
      | .rows[].c[$cols[$col].index] |= (objects.v |= clamp_max($max))
    ' input.json
    

    【讨论】:

    • 可能值得证明(或至少要注意)也可以将函数定义直接内联。让脚本只能由具有特定点文件内容的用户运行可能会适得其反。
    • 幸运的是,这并没有使内联它更难阅读。
    • @JeffMercado 感谢您抽出宝贵时间回答。在我看来,第二个代码块好像是您提到的内联版本,在这种情况下可能更可取。我收到一个错误,我很惭愧地说我不太明白。 jq: error: INDEX/2 is not defined at &lt;top-level&gt;, line 1: def clamp_max($maxInc): if . &gt; $maxInc then $maxInc else . end; (INDEX(.cols|to_entries[]|{id:.value.id,index:.key};.id)) as $cols | .rows[].c[$cols[$col].index] |= (objects.v |= clamp_max($max)) 好像列名是错误的,但是我已经三重检查了。
    • @LCB 我相信它已添加到 1.6 版中。您应该能够从 builtin.jq 复制实现,只要您有 1.5(它使用流式传输),它就应该可以工作。
    • 是的,先生,这就是问题所在。我正在使用 Debian Buster,我收到的 apt 版本是 jq-1.5-1-a5b5cbe。谢谢你的澄清。
    【解决方案2】:

    使用如下调用:

    jq --arg col Room2Set --argjson mx 72  --argjson mn 62 -f clamp.jq input.json
    

    clamp.jq 包含:

    def clamp: if . > $mx then $mx elif . < $mn then $mn else . end;
    
    (.cols | map(.id) | index($col)) as $ix
    | .rows[].c[$ix].v |= clamp
    
    

    选定的单元格应该被“夹住”。

    【讨论】:

    • 感谢您的回答。我能够让它满足我的需要,只需稍作改动以使其内联并夹紧上下(我忽略了要求):jq --arg col 'Room2Set' --argjson mx 62 --argjson mn 60 'def clamp: if . &gt; $mx then $mx elif . &lt; - $mn then - $mn else . end;(.cols | map(.id) | index($col)) as $ix | .rows[].c[$ix].v |= clamp' input.json 是有效的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-20
    • 1970-01-01
    • 2017-05-10
    • 1970-01-01
    相关资源
    最近更新 更多