对具有不均匀空格的空格分隔列表进行排序
Posted
技术标签:
【中文标题】对具有不均匀空格的空格分隔列表进行排序【英文标题】:Sorting a space delimited list with uneven spaces 【发布时间】:2021-12-19 02:35:08 【问题描述】:我有一个以空格分隔的列表,其中 将 是第一列的空格数量不均匀。我想按字符串后面出现的第一个数字对它进行反向排序。我需要使用 bash 命令来执行此操作。
例子:
Pontiac Firebird 19.0 6 250.0 100.0 3282. 15.0 71 US
Pontiac J2000 SE Hatchback 31.0 4 112.0 85.00 2575. 16.2 82 US
Oldsmobile Delta 88 Royale 12.0 8 350.0 160.0 4456. 13.5 72 US
Oldsmobile Omega 11.0 8 350.0 180.0 3664. 11.0 73 US
AMC Gremlin 20.0 6 232.0 100.0 2914. 16.0 75 US
AMC Gremlin 21.0 6 199.0 90.00 2648. 15.0 70 US
Pontiac Lemans V6 21.5 6 231.0 115.0 3245. 15.4 79 US
会变成:
Oldsmobile Omega 11.0 8 350.0 180.0 3664. 11.0 73 US
Oldsmobile Delta 88 Royale 12.0 8 350.0 160.0 4456. 13.5 72 US
Pontiac Firebird 19.0 6 250.0 100.0 3282. 15.0 71 US
AMC Gremlin 20.0 6 232.0 100.0 2914. 16.0 75 US
AMC Gremlin 21.0 6 199.0 90.00 2648. 15.0 70 US
Pontiac Lemans V6 21.5 6 231.0 115.0 3245. 15.4 79 US
Pontiac J2000 SE Hatchback 31.0 4 112.0 85.00 2575. 16.2 82 US
我试过sort -nr
来看看会发生什么,它会对列表进行反向排序,但相对于它的字母顺序。我想根据所有值进行排序。
诀窍是我必须用空格分隔。使用 bash 执行此操作的最佳方法是什么?
【问题讨论】:
您的意思是要对第一个全数字字段(可能包含小数)进行排序?所以你忽略了V6
中的6
,你忽略了J2000
中的2000
,对吧?如果“第一个全数字字段”中有重复项,我们应该怎么做,即是否有二级/三级字段用于排序?
@markp-fuso 是的,准确地说。如果“第一个全数字字段”中有重复项,我会假设我可以将这些重复项按任何顺序排列。
您确定“第一个全数字字段”标准有效吗?因为在Oldsmobile Delta 88 Royale 12.0 8 ...
行中,那是“88”,而不是“12.0”。
鉴于第一个以空格分隔的字符串是汽车模型,并且您需要高级排序功能,为什么不说服您的团队以可识别的结构化格式(如 CSV 或 TSV)存储这些数据?有人可能会花几分钟时间给你答案,但这些答案不太可能通过大量输入值的压力测试。
【参考方案1】:
我必须用空格分隔
你的意思是,结果必须再次用空格分隔,对吗?在处理过程中,您可以随意变换输入。
假设您知道文件中永远不会出现的字符,请使用 sed
按该字符分隔要排序的值,然后按该值排序,然后再次删除其他分隔符。 (这个过程基本上就是一个Schwartzian transform。)
这里我们使用铃铛字符\a
来分隔key 进行排序。该字符不太可能出现在文本文件中。
sed -E 's/ ([0-9]+\.[0-9]+) / \a\1\a /' | sort -t $'\a' -k2,2n | tr -d \\a
【讨论】:
我认为运算应该以防错格式存储数据。【参考方案2】:这是一个简短的 ruby 程序:
ruby -e '
puts IO.readlines(ARGV.shift, chomp: true)
.map |line|
fields = line.split
[fields[0..(fields.size - 9)].join(" ")] + fields[-8 .. -1]
.sort_by |row| row[1]
.map |row| row.join(" ")
.join("\n")
' file
【讨论】:
【参考方案3】:我将为此使用 GNU AWK
,如下所示,让 file.txt
内容为
Pontiac Firebird 19.0 6 250.0 100.0 3282. 15.0 71 US
Pontiac J2000 SE Hatchback 31.0 4 112.0 85.00 2575. 16.2 82 US
Oldsmobile Delta 88 Royale 12.0 8 350.0 160.0 4456. 13.5 72 US
Oldsmobile Omega 11.0 8 350.0 180.0 3664. 11.0 73 US
AMC Gremlin 20.0 6 232.0 100.0 2914. 16.0 75 US
AMC Gremlin 21.0 6 199.0 90.00 2648. 15.0 70 US
Pontiac Lemans V6 21.5 6 231.0 115.0 3245. 15.4 79 US
然后
awk 'BEGINFPAT="[0-9]*[.][0-9]*";PROCINFO["sorted_in"]="@ind_num_asc"arr[$1]=$0ENDfor(i in arr)print arr[i]' file.txt
输出
Oldsmobile Omega 11.0 8 350.0 180.0 3664. 11.0 73 US
Oldsmobile Delta 88 Royale 12.0 8 350.0 160.0 4456. 13.5 72 US
Pontiac Firebird 19.0 6 250.0 100.0 3282. 15.0 71 US
AMC Gremlin 20.0 6 232.0 100.0 2914. 16.0 75 US
AMC Gremlin 21.0 6 199.0 90.00 2648. 15.0 70 US
Pontiac Lemans V6 21.5 6 231.0 115.0 3245. 15.4 79 US
Pontiac J2000 SE Hatchback 31.0 4 112.0 85.00 2575. 16.2 82 US
解释:我通知 GNU AWK
该字段是 0 位或更多位,后跟文字点 ([.]
),后跟 0 位或更多位(注意:我假设第一个数字中总会有点,而不是点在带有名称的列中)并且该数组遍历应该是视为Predefined Array Scanning Orders之一。对于每一行,我添加到数组对中,键是第一个数字 ($1
),值是整行 ($0
)。在遍历所有行后,我 print
来自数组 arr
的值,其顺序观察选定的数组遍历。
(在 gawk 4.2.1 中测试)
【讨论】:
以上是关于对具有不均匀空格的空格分隔列表进行排序的主要内容,如果未能解决你的问题,请参考以下文章