我有很多表存储在平面文件中(在名为basepath
的目录中),我想检查它们的行数。我现在能做到的最好的是:
c:([] filename:system "ls ",basepath;
tablesize:count each get each hsym `$basepath,/:system "ls ",basepath)
它将每个表完全加载到内存中,然后执行计数(这很慢)。将其保存为扩展表是使其更快的唯一方法(因为我只加载1列并对其进行计数)还是q上有技巧可以使用?
感谢您的帮助
答案 0 :(得分:4)
如果将basepath定义为存储所有平面表的目录的路径字符串,则可以创建行计数字典,如下所示:
q)cnt:{count get hsym x}
q)filename:key hsym `$basepath
q)filename!cnt each filename
t| 2
g| 3
这是我在basepath目录中保存平面表t和g的地方。这使您不必使用效率通常较低的system
命令。
函数cnt
采用每个平面表的路径(作为符号)并返回行数,而不将其保存到内存中。
如果您可以控制将这些文件保存下来的过程,那么最好的解决方案是添加一个额外的步骤,即在保存原始数据的同时将行计数的元信息保存在单独的某个位置。这样一来,您可以快速从该文件访问表的大小,而不必每次都读取完整的tbale。
但是,请注意,为避免完全将它们拉入内存,您将不得不使用read1
并查看二进制数据的标头。正如您所说,最好另存为展开的表格并读入一列。
更新:我不建议这样做,强烈建议您执行上述操作,但是出于好奇,在考虑使用read1
之后,以下示例说明了一个骇人解决方案的外观:
f:{
b:read1(y;0;x);
if[not 0x62630b~b[2 4 5];'`$"not a table"];
cc:first first((),"i";(),4)1:b 7+til 4;
if[null ce:first where cc=sums 0x0=11 _ b;:.z.s[x*2;y]];
c:`$"\000" vs "c"$b[11+til ce];
n:first first((),"i";(),4)1:b[(20+ce)+til 4];
:`columns`rows!(c;n);
}[2000]
q二进制文件格式未在任何地方记录,找出它的唯一方法是保存不同的内容并查看字节如何变化。各个版本之间也可能会发生变化-以上内容是针对3.5编写的,可能仅对3.0-3.5有效,而对最新的3.6版本或任何2.X无效。
给定的代码以下列方式工作:
从文件开头读取一个块
验证它看起来像一个平坦的无键表(带有符号[11]键的字典[99]的翻转[98])
希望这能回答您的问题!
答案 1 :(得分:2)
从试验二进制文件开始,当您保存平面文件时,表计数似乎被保存为二进制文件的一部分,在初始对象类型和列标题之后占用了4个字节,这随表的不同而不同。桌子。
public float axisDir;
...
else if (spanCamera == 0 && axisDir == 1)
{
Camera.main.transform.RotateAround(rb.position, Vector3.up, -1 * Time.fixedDeltaTime * spanSpeed);
}
这应该有助于您了解Fiona发布的功能。
二进制文件保存在低位字节序中,这意味着最高有效字节是最右边的数字-用十进制表示数字100会得到001,其中100(最高有效)在右边,然后是10s最后是1s在二进制文件中,每两位两位是一个字节。
您可以使用`:test set ([]a:1 2 3;b:4 5 6;c:7 8 9;aa:10 11 12;bb:13 14 15)
q)read1 `:test
0xff016200630b000500000061006200630061610062620000000500000009000300000
0 7 11 31
bytes | example | meaning
---------------------------------------------------------------------------------------
0 - 5 | 0xff016200630b0 | object is a flat table
7 - 11 | 0x05000000 | number of columns (5)
12- 22 | 0x6100620063006161006262 | one byte for the ascii values of column "a" and "b" in hex followed by the one byte separator
23 - 30 | 0x0000050000000900 | 8 bytes that can be skipped
31 - 34 | 0x0300000 | 4 bytes for row count of first column (3)
读取二进制文件的内容,列表中的其他参数指定偏移量-从何处开始读取以及要读取多少字节。在我们的例子中,我们要从字节31开始读取4个字节,指定输出应为整数并将输入切成4个字节的单独块。
1:
将little-endian字节转换为long可以得到行数。由于只需读取4个字节而不是整个文件,因此速度要快得多。
对于具有10000行和2列的表,差别不大:
q)first first (enlist "i";enlist 4)1:(`:test;31;4)
3i
对于具有100m行和2列的表:
q)\t 0x0 sv reverse first (enlist "x";enlist 1)1:(`:test10000;31;4)
0
q)\t count get `:test10000
0
如果您有一张张开的表,则可以从字节9-13读取其中一列中的元素数量,就像这样,假设该列是一个简单列表:
q)\t 0x0 sv reverse first (enlist "x";enlist 1)1:(`:test10m;31;4)
0
q)\t count get `:test10m
2023
上阅读有关从二进制文件读取内容的更多信息。
答案 2 :(得分:1)
您可以使用以下方法来提高当前的效率
计数表:{计数每个获取每个hsym`$ basepath}
通过不包括额外读入的数据以及当前正在执行的联接,这将提高计数速度。您是正确的,尽管如果保存的表张开了,您只需要读入一栏中就可以提高效率。
答案 3 :(得分:0)
如果您的表未压缩地存储,则可能会遇到一些麻烦,您可以对文件标题中的read1进行处理,直到找到第一列标题为止。
但是v hacky:-(
您有责任将其保存下来吗?您可以像现在一样保持运行状态吗?