将链接列表转换为十字路口网格的 Power Query
Power Query to Convert List of Links to Grid of Crossings
在 Excel 中,我有一个用标识符标记的配对项目的数据 table。本质上,命名链接。
工作表:链接
Tag
Point-A
Point-B
Route 1
Home
Office
Route 2
Home
Grocery 1
Happy Hour
Office
Bar
Sad Hour
Office
Dump
Headaches
Bar
Pharmacy
Sick
Bar
Dump
Route 3
Office
Moms
Route 4
Office
Park
Victory
Park
Bar
Discard
Park
Dump
我想将此数据转换为行和列中所有点的网格,并将标记放置在交叉点(很像带有城市距离网格的旧纸质道路地图)
工作表:网格
A \ B
Bar
Dump
Grocery 1
Home
Home
Moms
Office
Office
Park
Pharmacy
Bar
Sick
Happy Hour
Victory
Headaches
Dump
Sick
Sad Hour
Discard
Grocery 1
Route 2
Home
Route 1
Home
Route 2
Moms
Route 3
Office
Happy Hour
Sad Hour
Route 1
Route 3
Office
Route 4
Park
Victory
Discard
Route 4
Pharmacy
Headaches
我写了下面的M
转换代码,但是好像有点任性,过头了。我是用点的位编码来构造连接键的,所以咬过程大概会突破32个点。
是否有更短的一组 LET
对网格进行相同的转换?
有没有办法创建一个 Min(Point-A,Point-B)
与 Max(Point-A,Point-B)
定界连接的密钥,从而不依赖 bitting?
M 代码(从高级编辑器复制)
let
LinksTable = Table.SelectRows(Excel.CurrentWorkbook(), each [Name] = "Links"),
Links = Table.RemoveColumns(Table.ExpandTableColumn(LinksTable, "Content", {"Tag", "Point-A", "Point-B"}), "Name"),
AllPoints = Table.Combine(
{ Table.SelectColumns(Table.RenameColumns(Links,{"Point-A", "Point"}), "Point"),
Table.SelectColumns(Table.RenameColumns(Links,{"Point-B", "Point"}), "Point")
}),
ThePoints = Table.Sort(Table.Distinct(AllPoints),{"Point"}),
PointsIndexed = Table.AddIndexColumn(ThePoints, "Index", 0, 1, Int64.Type),
PointsBitted = Table.RemoveColumns(Table.AddColumn(PointsIndexed, "Bit", each Number.Power(2, [Index]), Int64.Type),"Index"),
AllPairsBitted = Table.Join(
Table.RenameColumns(PointsBitted, {{"Point", "Point-A"}, {"Bit", "Bit-A"}}), {},
Table.RenameColumns(PointsBitted, {{"Point", "Point-B"}, {"Bit", "Bit-B"}}), {},
JoinKind.FullOuter
),
AllPairsKeyed = Table.RemoveColumns(
Table.AddColumn(AllPairsBitted, "BitKeyPair", each Number.BitwiseOr([#"Bit-A"],[#"Bit-B"])),
{ "Bit-A", "Bit-B"}
),
#"Links-A-Bitted" = Table.Join(
Links, "Point-A",
Table.RenameColumns(PointsBitted,{{"Point", "Point-A"}, {"Bit", "Bit-A"}}), "Point-A"
),
#"Links-AB-Bitted" = Table.Join(
#"Links-A-Bitted", "Point-B",
Table.RenameColumns(PointsBitted,{{"Point", "Point-B"}, {"Bit", "Bit-B"}}), "Point-B"
),
LinksKeyed = Table.RemoveColumns(
Table.AddColumn(#"Links-AB-Bitted", "BitKeyLink", each Number.BitwiseOr([#"Bit-A"],[#"Bit-B"])),
{ "Bit-A", "Bit-B"}
),
AllPairsTagged = Table.Sort( Table.RemoveColumns(
Table.Join(
AllPairsKeyed, "BitKeyPair",
Table.SelectColumns(LinksKeyed, {"BitKeyLink", "Tag"}), "BitKeyLink",
JoinKind.LeftOuter
),
{"BitKeyPair", "BitKeyLink"}
),
{"Point-A", "Point-B"}
),
Grid = Table.Pivot(AllPairsTagged, List.Distinct(AllPairsTagged[#"Point-B"]), "Point-B", "Tag", List.First)
in
Grid
我认为您可以使用 PIVOT
来实现这一点。直接使用此功能将不起作用,因为您正在寻找列和行的对称性。
诀窍是强制对称,将 Point-B
中的值附加到 Point-A
的值中。
步骤
- 创建一个辅助 table 并以与原始 table 相反的方式对列重新排序,因此
Tag
、Point-B
和 Point-A
。
- 在辅助 table 上,按顺序将列重命名为
Tag
、Point-A
和 Point-B
。 Append
通常按字面意思使用列名,因此如果不重命名,它会附加相同列的名称。
Pivot
列 Point-B
没有聚合数据。
- 使用
Point-A
作为参考对列重新排序,使列和行对称。
值得一提的是 Buffer
来源 table 是一个很好的做法,因为它在整个计算过程中被多次使用。
计算
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("Zc69CsMgEMDxVwnOLv14ghKoS2looEvIcJwXIkEMZxx8+6axiUInwd/99bpOvFxYqDoJKZSztB7PYTBIope7nbPd2SFxXMe/rGCeY6Vc4JxJcQPetAX9Z3Wwc0oJNOBI/hdI0YzAFjCm1uB0yBGldS7lgw9nfWHX0hrgabO3wcVx3K/yirXxCKwzpK/6Dw==", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [Tag = _t, #"Point-A" = _t, #"Point-B" = _t]),
BufferedSource = Table.Buffer(Source),
SecondTable = Table.ReorderColumns(BufferedSource,{"Tag","Point-B","Point-A"}),
SecondTableRenameCols = Table.RenameColumns(SecondTable,{{"Point-A","Point-B"},{"Point-B","Point-A"}}),
AppendTables = Table.Combine({BufferedSource,SecondTableRenameCols}),
PivotTables = Table.Pivot(AppendTables, List.Distinct(AppendTables[#"Point-B"]), "Point-B", "Tag"),
ReorderCols = Table.ReorderColumns( PivotTables, PivotTables[#"Point-A"])
in ReorderCols
输出
Point-A
Bar
Dump
Grocery 1
Home
Moms
Office
Park
Pharmacy
Bar
Sick
Happy Hour
Victory
Headaches
Dump
Sick
Sad Hour
Discard
Grocery 1
Route 2
Home
Route 2
Route 1
Moms
Route 3
Office
Happy Hour
Sad Hour
Route 1
Route 3
Route 4
Park
Victory
Discard
Route 4
Pharmacy
Headaches
在 Excel 中,我有一个用标识符标记的配对项目的数据 table。本质上,命名链接。
工作表:链接
Tag | Point-A | Point-B |
---|---|---|
Route 1 | Home | Office |
Route 2 | Home | Grocery 1 |
Happy Hour | Office | Bar |
Sad Hour | Office | Dump |
Headaches | Bar | Pharmacy |
Sick | Bar | Dump |
Route 3 | Office | Moms |
Route 4 | Office | Park |
Victory | Park | Bar |
Discard | Park | Dump |
我想将此数据转换为行和列中所有点的网格,并将标记放置在交叉点(很像带有城市距离网格的旧纸质道路地图)
工作表:网格
A \ B | Bar | Dump | Grocery 1 | Home | Home | Moms | Office | Office | Park | Pharmacy |
---|---|---|---|---|---|---|---|---|---|---|
Bar | Sick | Happy Hour | Victory | Headaches | ||||||
Dump | Sick | Sad Hour | Discard | |||||||
Grocery 1 | Route 2 | |||||||||
Home | Route 1 | |||||||||
Home | Route 2 | |||||||||
Moms | Route 3 | |||||||||
Office | Happy Hour | Sad Hour | Route 1 | Route 3 | ||||||
Office | Route 4 | |||||||||
Park | Victory | Discard | Route 4 | |||||||
Pharmacy | Headaches |
我写了下面的M
转换代码,但是好像有点任性,过头了。我是用点的位编码来构造连接键的,所以咬过程大概会突破32个点。
是否有更短的一组 LET
对网格进行相同的转换?
有没有办法创建一个 Min(Point-A,Point-B)
与 Max(Point-A,Point-B)
定界连接的密钥,从而不依赖 bitting?
M 代码(从高级编辑器复制)
let
LinksTable = Table.SelectRows(Excel.CurrentWorkbook(), each [Name] = "Links"),
Links = Table.RemoveColumns(Table.ExpandTableColumn(LinksTable, "Content", {"Tag", "Point-A", "Point-B"}), "Name"),
AllPoints = Table.Combine(
{ Table.SelectColumns(Table.RenameColumns(Links,{"Point-A", "Point"}), "Point"),
Table.SelectColumns(Table.RenameColumns(Links,{"Point-B", "Point"}), "Point")
}),
ThePoints = Table.Sort(Table.Distinct(AllPoints),{"Point"}),
PointsIndexed = Table.AddIndexColumn(ThePoints, "Index", 0, 1, Int64.Type),
PointsBitted = Table.RemoveColumns(Table.AddColumn(PointsIndexed, "Bit", each Number.Power(2, [Index]), Int64.Type),"Index"),
AllPairsBitted = Table.Join(
Table.RenameColumns(PointsBitted, {{"Point", "Point-A"}, {"Bit", "Bit-A"}}), {},
Table.RenameColumns(PointsBitted, {{"Point", "Point-B"}, {"Bit", "Bit-B"}}), {},
JoinKind.FullOuter
),
AllPairsKeyed = Table.RemoveColumns(
Table.AddColumn(AllPairsBitted, "BitKeyPair", each Number.BitwiseOr([#"Bit-A"],[#"Bit-B"])),
{ "Bit-A", "Bit-B"}
),
#"Links-A-Bitted" = Table.Join(
Links, "Point-A",
Table.RenameColumns(PointsBitted,{{"Point", "Point-A"}, {"Bit", "Bit-A"}}), "Point-A"
),
#"Links-AB-Bitted" = Table.Join(
#"Links-A-Bitted", "Point-B",
Table.RenameColumns(PointsBitted,{{"Point", "Point-B"}, {"Bit", "Bit-B"}}), "Point-B"
),
LinksKeyed = Table.RemoveColumns(
Table.AddColumn(#"Links-AB-Bitted", "BitKeyLink", each Number.BitwiseOr([#"Bit-A"],[#"Bit-B"])),
{ "Bit-A", "Bit-B"}
),
AllPairsTagged = Table.Sort( Table.RemoveColumns(
Table.Join(
AllPairsKeyed, "BitKeyPair",
Table.SelectColumns(LinksKeyed, {"BitKeyLink", "Tag"}), "BitKeyLink",
JoinKind.LeftOuter
),
{"BitKeyPair", "BitKeyLink"}
),
{"Point-A", "Point-B"}
),
Grid = Table.Pivot(AllPairsTagged, List.Distinct(AllPairsTagged[#"Point-B"]), "Point-B", "Tag", List.First)
in
Grid
我认为您可以使用 PIVOT
来实现这一点。直接使用此功能将不起作用,因为您正在寻找列和行的对称性。
诀窍是强制对称,将 Point-B
中的值附加到 Point-A
的值中。
步骤
- 创建一个辅助 table 并以与原始 table 相反的方式对列重新排序,因此
Tag
、Point-B
和Point-A
。 - 在辅助 table 上,按顺序将列重命名为
Tag
、Point-A
和Point-B
。Append
通常按字面意思使用列名,因此如果不重命名,它会附加相同列的名称。 Pivot
列Point-B
没有聚合数据。- 使用
Point-A
作为参考对列重新排序,使列和行对称。
值得一提的是 Buffer
来源 table 是一个很好的做法,因为它在整个计算过程中被多次使用。
计算
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("Zc69CsMgEMDxVwnOLv14ghKoS2looEvIcJwXIkEMZxx8+6axiUInwd/99bpOvFxYqDoJKZSztB7PYTBIope7nbPd2SFxXMe/rGCeY6Vc4JxJcQPetAX9Z3Wwc0oJNOBI/hdI0YzAFjCm1uB0yBGldS7lgw9nfWHX0hrgabO3wcVx3K/yirXxCKwzpK/6Dw==", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [Tag = _t, #"Point-A" = _t, #"Point-B" = _t]),
BufferedSource = Table.Buffer(Source),
SecondTable = Table.ReorderColumns(BufferedSource,{"Tag","Point-B","Point-A"}),
SecondTableRenameCols = Table.RenameColumns(SecondTable,{{"Point-A","Point-B"},{"Point-B","Point-A"}}),
AppendTables = Table.Combine({BufferedSource,SecondTableRenameCols}),
PivotTables = Table.Pivot(AppendTables, List.Distinct(AppendTables[#"Point-B"]), "Point-B", "Tag"),
ReorderCols = Table.ReorderColumns( PivotTables, PivotTables[#"Point-A"])
in ReorderCols
输出
Point-A | Bar | Dump | Grocery 1 | Home | Moms | Office | Park | Pharmacy |
---|---|---|---|---|---|---|---|---|
Bar | Sick | Happy Hour | Victory | Headaches | ||||
Dump | Sick | Sad Hour | Discard | |||||
Grocery 1 | Route 2 | |||||||
Home | Route 2 | Route 1 | ||||||
Moms | Route 3 | |||||||
Office | Happy Hour | Sad Hour | Route 1 | Route 3 | Route 4 | |||
Park | Victory | Discard | Route 4 | |||||
Pharmacy | Headaches |