本篇介紹 Power Query M 語言的三種結(jié)構(gòu)化類型(或稱為容器類型):List、Record 和 Table,它們是 Power Query 數(shù)據(jù)處理的核心。了解本篇三種容器類型后,應(yīng)該能大體看懂查詢編輯器和高級(jí)編輯器中的代碼邏輯。
List
List 中文翻譯為列表,跟 Python 語言的 list 很類似,由一序列有順序的元素構(gòu)成,這些元素可以是不同的數(shù)據(jù)類型。M 語言的 List 由一對(duì)大括號(hào)來,每個(gè)元素之間用逗號(hào)分隔。
A List is a zero-based ordered sequence of values enclosed in curly brace characters { }. The curly brace characters { } are also used to retrieve an item from a List by index position.
定義一個(gè)由 1 到 5 的整數(shù)組成的 List:
{1, 2, 3, 4, 5} // 由 1 到 5 的整數(shù)構(gòu)成的 List
我們?cè)?strong>查詢編輯器中來看一下。創(chuàng)建一個(gè)空白查詢(請(qǐng)參考上一篇如何創(chuàng)建空查詢),然后在公式欄中輸入 {1, 2, 3, 4, 5},點(diǎn)擊"對(duì)號(hào)"確認(rèn)。
確認(rèn)后,查詢編輯器的顯示區(qū)顯示了列表的值,左邊是索引:
切換到功能區(qū)【主頁(yè)】,點(diǎn)擊【關(guān)閉并上載】,看看 Excel Sheet 中列表的顯示效果。
M 語言提供
.. 符號(hào)表示表示連續(xù)的元素,比如從 1 到 100:
{1..100}
連續(xù)符號(hào)不僅僅被用作數(shù)字,也可以用于單個(gè)字符,比如我們想列出所有的字母,包括大寫字母和小寫字母:
{"a".."z", "A".."Z"}
Power Query (PQ) 為什么能夠理解從 a 到 z 呢,背后的原理就是這些字母的 Unicode 的編碼,中文的 Unicode 編碼大致范圍在 19968-40891 之間,所以,我們也可以構(gòu)造出所有中文(包括漢字和字符)字的列表:
List.Transform({19968..40891}, Character.FromNumber)
List 的元素是有順序的,使用從 0 開始的索引獲取 List 中的元素:
numbers = {1..10}
first = numbers{0} // first element
last = numbers{9} // last element
如果有更復(fù)雜條件的存取,需要用到標(biāo)準(zhǔn)庫(kù)的函數(shù),比如:
- List.First
- List.Last
- List.FirstN
- List.LastN
假設(shè)有一個(gè)從 1 到 100 的列表,要取出列表最后的 5 個(gè)元素:
let
source = {1..100},
lastFive = List.LastN(source, 5)
in
lastFive
Record (記錄)
Record 類似于 Python 中的 dict,用于表達(dá)有鍵值對(duì) (key-value pair) 的數(shù)據(jù)。Record 用一對(duì)中括號(hào) [] 來包含,不同鍵值對(duì)用逗號(hào)分隔,鍵 (key)沒有引號(hào):
A Record is a set of fields. A field is a name/value pair where the name is a text value that is unique within the field’s record.
let
Product = [Product="TV", Price=1800]
in
Product
將列表上載到 Excel Sheet 中的效果:
Record 是鍵值對(duì),使用 key 來讀取 Record 中的值,比如:
let
source = [Product="TV", Price=1800],
product = source[Product]
in
product
通常情況下,我們的數(shù)據(jù)都是由行和列構(gòu)成的表格形式,對(duì)于這種格式,可以用 List 和 Record 組合來表示,每一行是一個(gè) Record,多個(gè) Record 組成一個(gè) List:
let
products = {
[product="TV", price=1800],
[product="Computer", price=6800]
}
in
products
在查詢編輯器中的顯示如下:
如果我們讀取 Computer 的價(jià)格:
products{1}[price]
let
products = {
[product="TV", price=1800],
[product="Computer", price=6800]
},
computerPrice = products{1}[price]
in
computerPrice
Table (查詢表)
Table 是由行和列構(gòu)成的數(shù)據(jù)集合,一般 Table 都是從外部數(shù)據(jù)源導(dǎo)入到 PQ 中,但也可以用 M 腳本手工創(chuàng)建。
A Table is a set of values organized into named columns and rows. The column type can be implicit or explicit.
手工創(chuàng)建 table 的基本方法是按行構(gòu)建:
products = #table(
// columns
{
"Product", "Price"
},
// lines
{
{"TV", 1800},
{"Computer", 5600}
}
查詢編輯器界面的顯示:
上面創(chuàng)建查詢表的方法,沒有指定數(shù)據(jù)類型,用下面的語法創(chuàng)建 Table 的同時(shí),指定 Column 的數(shù)據(jù)類型:
let
products = #table( type table
// columns
[
Product = text, Priece = number
],
// lines
{
{"TV", 1800},
{"Computer", 5600}
}
)
in
products
標(biāo)準(zhǔn)庫(kù)中提供了 Table.FromXXX 函數(shù)來創(chuàng)建 Table,可以根據(jù)需要來學(xué)習(xí),這里提供其中的兩種:
Table.FromRecords()
語法:
Table.FromRecords(records as list,
optional columns as any,
optional missingField as nullable number) as table
將 records 或者 record 構(gòu)成的 list 轉(zhuǎn)換成 table,可以理解為按行構(gòu)建 table。舉一個(gè)例子:
let
scores = {
[Name="張三", Subject="語文", Score= 98],
[Name="李四", Subject="語文", Score= 90],
[Name="張三", Subject="數(shù)學(xué)", Score= 100],
[Name="李四", Subject="數(shù)學(xué)", Score= 87],
[Name="張三", Subject="英語", Score= 60],
[Name="李四", Subject="英語", Score= 72]
},
source = Table.FromRecords(scores)
in
source
Table.FromColumns()
按列構(gòu)建一個(gè) table,需要一個(gè) list 作為參數(shù),語法如下:
Table.FromColumns(lists as list, optional columns as any) as table
上面的示例數(shù)據(jù),使用 Table.FromColumns() 函數(shù)構(gòu)建:
let
source = Table.FromColumns(
{
{"張三","李四", "張三","李四","張三","李四"},
{"語文","語文","數(shù)學(xué)","數(shù)學(xué)", "英語","英語"},
{98,90,100,87,60, 72}
},
{"Name", "Subject", "Score"}
)
in
source
獲取行的值
Table 每一行是一個(gè) record 類型的數(shù)據(jù),所有行可以看成由 record 構(gòu)成的 list:
products = {
[product="TV", price=1800],
[product="Computer", price=6800]
},
Table 每一列是 list 類型的數(shù)據(jù),所有列可以看成由 list 構(gòu)成的 record:
products = [
Product={"TV", "Computer"},
Price={1800, 5600}
]
上面兩句如何看待行和列的方式是理解讀取 table 中行、列和單元格值的基礎(chǔ)。怎么讀取行的數(shù)據(jù)呢?比如我們要讀取第一行所有列,可以這樣:
navigation = products{0} // 第一行所有列
獲取列的值
比如上面的表,想獲取 Product 整列的數(shù)據(jù)
prodName = products[Product]
獲取單元格的值
在上面方法,能獲取到行或列之后,獲取單元格的值就比較簡(jiǎn)單了:
productName = products{0}[Product] // 先讀取行 (record),再根據(jù) record 的 key 讀取
productName = products[Product]{0} // 先讀取列 (list),再根據(jù) list 的索引讀取
還有一種更直觀的方式,這種方式比較直觀,盡量應(yīng)該采用這種方法:
productName = products{[Product="TV"]}