原文Org tutorial on table lookup functions, 由 Jarmo Hurri 编辑,维护。本文只做学习之用。
序言
Org
提供三个不同的函数,用于在表中执行搜索和数据依赖的计算。 这些函数可以用于实现数组关联,统计匹配单元格,结果排名或分组数据。 以下示例将有助于开始使用这些功能。
具有唯一键的关联数组
查找最直接的用法是将 Org
表的一部分视为关联数组:一个键可用于查找相应的值。
假设你去斯堪的纳维亚,并且想跟踪你花了多少钱在旅途中。 你决定将所有金额转换为欧元。 在行程之前,你请记下大致汇率,如下表所示:
#+TBLNAME: rates
| currency | abbreviation | euros |
|-----------------+--------------+-------|
| euro | eur | 1 |
| Norwegian krone | nok | 0.14 |
| Swedish krona | sek | 0.12 |
| US dollar | usd | 0.77 |
接下来将使用函数 org-lookup-first
和前面的汇率表格来自动将不同货币的金额转换成欧元。 函数 org-lookup-first
的签名如下:
(org-lookup-first VAL S-LIST R-LIST &optional PREDICATE)
假定 PREDICATE
为 nil
,在这种情况下使用默认谓词(predicate) equal
, 则该函数将在 S-LIST
中搜索 VAL
的第一个实例,并从 R-LIST
中的相应位置返回一个值。 在下表中,每笔金额分配了货币缩写; 对于相应的缩写,在汇率表格的第二列中进行查找,然后从第三列返回相应的汇率。 对于每一行只需要填充前四列; 第5列和第6列自动计算产生。 请注意,如果找不到键值,则会出现错误:在最后一行中,空键将被搜索。
| date | expense | sum | currency | rate | euros |
|-------+------------------+------+----------+--------+--------|
| 1.3. | flights | 324 | eur | 1 | 324 |
| 4.6. | books and maps | 243 | usd | 0.77 | 187.11 |
| 30.7. | rental car | 8300 | sek | 0.12 | 996. |
| 2.7. | hotel | 1150 | sek | 0.12 | 138. |
| 2.7. | lunch | 190 | sek | 0.12 | 22.8 |
| 3.7. | fishing licenses | 1400 | nok | 0.14 | 196. |
| 3.7. | gasoline | 340 | | #ERROR | #ERROR |
#+TBLFM: $5='(org-lookup-first $4 '(remote(rates,@2$2..@>$2)) '(remote(rates,@2$3..@>$3)))::$6=$5*$3
多个匹配优先排序
教师的常见任务是从总分中分配考试成绩。 这种分级的起点是具有等级边界的表。 以下是一个这样的表,其中行按照特定等级所需的下限的递增排序。
#+TBLNAME: grade-boundaries
| lower bound | grade |
|-------------+-------|
| 0 | F |
| 10 | D |
| 20 | C |
| 30 | B |
| 40 | A |
使用函数 org-lookup-last
和根据前面的 等级边界
表来为学生分配成绩。 函数 org-lookup-last
的签名与 org-lookup-first
的完全相同:
(org-lookup-last VAL S-LIST R-LIST &optional PREDICATE)
函数 org-lookup-last
会搜索 S-LIST
中的最后一个匹配项,并从 R-LIST
中的相应位置返回一个值。 用于分配等级的查找思想如下:假定学生的考试成绩是33分。我们寻找学生的 marks 大于或等于下限的表中的最后一行; 在这种情况下,它是下边界的行30。学生的成绩是第二列的相应元素,在这种情况下是B.
因此,给定学生的标记数VAL,找到下限S满足 (>= VAL S)
的表等级边界的第一列的最后一行。 因此,我们将使用 >=
作为 PREDICATE
来执行匹配。 注意, VAL
和 S
按照它们在 org-lookup-last
的签名中的顺序被分配给谓词,其中 VAL
在 S-LIST
之前。 下表列出了从总 marks 到最终成绩的转换。 注: 文字插值 L
表示表值的字面值插入到Elisp公式中,这是必须的,因为一些值是数字,一些是符号。
| student | marks | grade |
|---------+-------+-------|
| X | 30 | B |
| Y | 29 | C |
| Z | 5 | F |
| W | 55 | A |
#+TBLFM: $3='(org-lookup-last $2 '(remote(grade-boundaries,@2$1..@>$1)) '(remote(grade-boundaries,@2$2..@>$2)) '>=);L
统计匹配单元格
函数 org-lookup-all
不能在表等式中使用自己,因为它返回值列表。 但是,通过将函数与其他 elisp 函数相结合,可执行强大的查找任务。
作为一个简单的例子,计算表中缺少值的数量。 函数 org-lookup-all
的签名与其他两个查找函数的签名完全相同:
(org-lookup-all VAL S-LIST R-LIST &optional PREDICATE)
数搜索 S-LIST
中的所有匹配项,并从 R-LIST
中的相应位置返回所有相应的值。 与org-lookup-first和org-lookup-last的情况一样,如果 R-LIST
为nil,则直接返回 S-LIST
相应匹配值。 注意使用 E
标志来保留范围内的空字段。 还要注意,在这种情况下,以真正的二维范围来进行查找,这也是可能的
| group | round 1 | round 2 |
|-------+---------+---------|
| A | | 2.4 |
| B | 4.7 | 11 |
| C | | |
| D | 5 | |
| E | | 7.2 |
| F | 3.2 | 4.3 |
| G | | 4.4 |
| H | | 8 |
|-------+---------+---------|
| total | missing | 7 |
#+TBLFM: @>$3='(length(org-lookup-all "" '(@2$2..@-1$3) nil));E
排序结果
org-lookup-all
的另一个示例应用是结果的自动排序。 在下表中,总数越大越好。 请注意,Elisp表达式还自动处理关联关系。
| group | marks | rank |
|-------+-------+------|
| A | 22 | 2 |
| B | 22 | 2 |
| C | 14 | 4 |
| D | 28 | 1 |
| E | 9 | 5 |
#+TBLFM: $3='(+ 1 (length (org-lookup-all $2 '(@2$2..@>$2) nil '<)));N
统计原始数据的频率
数据分析中的常见情况是对可视化的原始数据值进行分类(分组)。 通常是通过统计在特定范围内的出现频率来完成的。 可使用函数 org-lookup-all
,结合其他 elisp 函数来执行此任务。 此示例还显示了如何使用表中的多个值构建更复杂的查找规则。
考虑下表,不同组A-I的不同结果。
#+TBLNAME: raw-data
| group | result |
|-------+--------|
| A | 2.3 |
| B | 4.2 |
| C | 1.1 |
| D | 3.6 |
| E | 4.5 |
| F | 2.4 |
| G | 1.0 |
| H | 2.3 |
| I | 2.8 |
将结果分为不同的,并且相斥的类。 例如,属于第一类的值在区间 [1,1.9]
(包括端点)中。 为了执行这样的分类,我们定义了以下两参数谓词函数 in-interval
。 请注意,此函数的第一个参数是一对,其第一个元素是下限,第二个成员是该间隔的上限。
#+BEGIN_SRC emacs-lisp
(defun in-interval (bounds el)
(and (>= el (car bounds)) (<= el (cadr bounds))))
#+END_SRC
#+RESULTS:
: in-interval
使用这个谓词函数,我们可以构造一个具有分类边界和相应频率的表。 请注意,函数 org-lookup-all
的第一个参数是作为第一个参数传递给谓词 in-interval
中的第一个参数,是一对边界。
| lower bound | upper bound | frequency |
|-------------+-------------+-----------|
| 1 | 1.9 | 2 |
| 2 | 2.9 | 4 |
| 3 | 3.9 | 1 |
| 4 | 4.9 | 2 |
#+TBLFM: $3='(length (org-lookup-all '($1 $2) '(remote(raw-data,@2$2..@>$2)) nil 'in-interval));N
结论
Org 的 lookup
函数可用于大量不同的数据相关计算。 例如,libreoffice或Excel用户熟悉的以下电子表格操作都可以使用它们来实现: HLOOKUP
, VLOOKUP
, COUNTIF
, SUMIF
和 FREQUENCY
。