使用命令行工具对JSON/JavaScript元组进行排序

11

我有一个JavaScript元组的列表,每行一个,存在一个文件中,格式如下:

{ x : 12, y : -1.0, as : [ 2, 0, 0 ], str : "xxx", d : 0.041 },
{ x : 27, y : 11.4, as : [ 1, 1, 7 ], str : "yyy", d : 0.235 },
{ x : -4, y :  2.0, as : [ 7, 8, 3 ], str : "zzz", d : 0.002 },
{ x : 44, y :  5.4, as : [ 9, 4, 6 ], str : "kkk", d : 0.176 },

我希望能够根据给定字段的值(在我的示例中是d字段)对它们进行排序,最好使用命令行工具(这是一个包含许多步骤的过程的一部分)。

如果有任何区别,我们可以假设所有行的长度完全相同(我可以知道d值的起始和结束索引),尽管我更喜欢不依赖于此的解决方案。


2
你所发布的不是有效的JSON格式。请通过引用键来更正语法,或告诉我们你并没有真正使用JSON。 - John Zwinck
5个回答

22

这个问题的提问和回答已经过去了一段时间。

现在,一种基于工具的方式是使用类似于jq的东西:

cat data.json | jq 'sort_by(.d)' >> data_sorted.json

欲了解更多信息,请查看网站:

jq 就像 JSON 数据的 sed - 你可以使用它来剪切、过滤、映射和转换结构化数据,就像 sed、awk、grep 和其他工具让你处理文本数据一样方便。

-https://stedolan.github.io/jq/

如果出于某些原因您不喜欢 jq,还有许多替代品:


5
sort_by 断言输入是一个数组。如果文件的每一行都是一个 JSON 对象,且你想要按某些字段对行进行排序,你可以使用 cat sample.json | jq -s -c 'sort_by(.d) | .[]' 进行排序。选项 -s 将读取所有行并将其存储为一个数组。从 http://bigdatums.net/2016/11/29/sorting-json-by-value-with-jq/ 中获取这个想法。 - ryan
可能 cat data.json | jq '.' -S 也能达到你想要的效果。 - Brad Parks

4

如果您可以保证所有字段的大小相同,那么您可以使用“sort”命令。例如,以下命令将根据x值按数字排序。

cat <your file.dat> | sort -n -k 5,7

您所提供的示例数据不是有效的JSON格式,而是JavaScript语法。一种方法是将文件包装成有效的JavaScript程序,并在node.js命令行中运行它。
var l = [
    { x : 12, y : -1.0, as : [ 2, 0, 0 ], str : "xxx", d : 0.041 },
    { x : 27, y : 11.4, as : [ 1, 1, 7 ], str : "yyy", d : 0.235 },
    ...
]
l.sort(function(o1, o2) { return o1.d < o2.d ? -1 : 1 });
console.log(l);

2

虽然这是一种取巧的方法,但如果每个JSON记录都是一行,并且您知道d的值在每行中以相同数量的空格分隔标记之后开始,那么您可以直接使用以下方法:

sort -g -k 20 < in > out

这将基于第20个以空格分隔的组件对行进行数字比较。 为了增加舒适性,您可以使用-t指定不同的分隔符(例如:),并根据需要调整-k参数,但这仍然是一种hack :)

sort通常经过精心优化以提高速度,因此您不太可能找到更快的替代品。


1
如果输入数据中每行都是一个JSON(如问题所示),那么@Ashley Coolman的解决方案不起作用,如此处所述:

使用jq按值对JSON进行排序可以通过使用sort_by()函数轻松完成。使用sort_by()函数的主要技巧是您的JSON输入必须在数组中。有多种方法可以在jq中执行此操作(如果您的数据尚未如此),包括使用-s或--slurp选项。--slurp选项将读取所有JSON输入到JSON数组中。从此时开始,数据可以按值排序。您可以使用.[]语法返回数组的所有元素。

这意味着问题中的数据的正确解决方案如下:
cat data.json | jq -s -c 'sort_by(.d) | .[]' >> data_sorted.json

0
您也可以使用GNU的sort,方法如下:
$ sort -t: -k6 -n test.csv
{ x : -4, y :  2.0, as : [ 7, 8, 3 ], str : "zzz", d : 0.002 },
{ x : 12, y : -1.0, as : [ 2, 0, 0 ], str : "xxx", d : 0.041 },
{ x : 44, y :  5.4, as : [ 9, 4, 6 ], str : "kkk", d : 0.176 },
{ x : 27, y : 11.4, as : [ 1, 1, 7 ], str : "yyy", d : 0.235 },

-k标志接受列索引。-t:表示使用:作为分隔符,-n是数字。

当然,如果在d之后添加另一个字段,则此解决方法将无法正常工作。如果出现这种情况,您可以更改-k的值,以仅考虑特定字符,例如-k6.2,6.6,但这将假设小数点后的位数恰好为3个。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接