某游戏的角色强弱由武力,统率,智力,敏捷和运气这五个指标决定。该游戏会出现十三个特殊情景,每当进入这些情景玩家就会面临多个选择并需要从中挑选一个出来。根据游戏的攻略,每一个选项都会对某角色的武力,统率,智力,敏捷和运气产生不同程度的影响,具体的数据如下图所示:
现要求计算出每一个组合的路径图以及对五围的累计影响,如下图所示:
从直觉出发,这个问题应该使用Table.AddColumn()或者List.TransformMany()产生笛卡尔积进行解答。遗憾的是, 即使只有十三个情景, 采用这种思路进行解题的运行时间会长得令人难以接受。因此,有必要从另一个角度理解这个问题:从游戏的角度出发,每一个情景的出现实际上是有先后的次序。如果我们把先后的次序理解为一种从属的关系(比如:情景二从属于情景一,情景三从属于情景二,如此类推),不难发现应该借鉴BOM树形结构分解(详情请查阅施阳老师同标题的文章)的思路进行解题。为了方便进行分步解释,问题会暂时化简为只有两个特殊情景,并为了与最终答案保持一致,会保留一些多余的步骤。第一步,需要定义如下常数串列:
Constant_List = { "武力", "统率", "智力", "敏捷", "运气" }
第二步,需要把武力,统率,智力,敏捷和运气这五列通过Table.CombineColumnsToRecord()转化为内嵌的记录:
Columns_To_Record = Table.CombineColumnsToRecord( Dataset, "nList", Constant_List )
第三步,需要通过Table.TransformColumns()把内嵌的记录转化为内嵌的复合串列:
Record_To_nList = Table.TransformColumns( Columns_To_Record, { "nList", each {Record.ToList(_)}, type list } )
第四步,把情景一的选择分离出来并更改部分列名:
fScenario = Table.RenameColumns( Table.SelectRows( Record_To_nList, each [情景] = 1 ), { { "选项", "路径" }, { "nList", "五围" } } )
第五步,把其他情景的选项分离出来:
oScenario = Table.SelectRows( Record_To_nList, each [情景] ˃ 1 )
第六步,通过Table.AddColumn()为大于1的情景计算出上一情景:
Previous_Scenarios = Table.AddColumn( oScenario, "上一情景", each [情景] - 1, Int64.Type )
第七步,以内连接把第六步所得的表格与第四步所得的表格连接起来, 匹配的行会以表格的形式内嵌于nTable列:
InnerJoin = Table.NestedJoin( Previous_Scenarios, "上一情景", fScenario, "情景", "nTable", JoinKind.Inner )
第八步,展开nTable列中的部分列并为这些列更改名字:
Expansion = Table.ExpandTableColumn( InnerJoin, "nTable", { "路径", "五围" }, { "上一路径", "上一五围" } )
第九步,计算路径图:
Add_Path = Table.AddColumn( Expansion, "路径", each Text.Combine( { [上一路径], [选项] }, "|" ), type text )
第十步,通过List.Combine()组合当前的五围数据与之前的五围数据:
Add_Summation = Table.AddColumn( Add_Path, "五围", each List.Combine( { [上一五围], [nList] } ), type list )
第十一步,通过Table.SelectColumn()移除情景,路径和五围之外的列。
RemoveCols = Table.SelectColumns( Add_Summation, { "情景", "路径", "五围" } )
第十二步,利用List.Zip()实现行列转换后计算对五围的累计影响并转化结果为内嵌的记录:
TransCol = Table.TransformColumns( RemoveCols, { "五围", (x)=˃ Record.FromList( List.Transform( List.Zip( x ), (y)=˃ List.Sum(y) ), Constant_List ), type record } )
第十三步,展开内嵌记录中的所有字段:
Expand_Records = Table.ExpandRecordColumn( TransCol, "五围", Constant_List )
第十四步,移除情景列:
RemoveCol = Table.RemoveColumns( Expand_Records, "情景" )
第十五步,修改新列的数据类型:
DataType = Table.TransformColumnTypes( RemoveCol, List.Zip( { Constant_List, List.Repeat( {Int64.Type}, List.Count(Constant_List) ) } ) )
回到原来十三个情景的问题上,只需要利用List.Accumulate()重复以上的第七到第十一步就可以完成解答,完整代码如下:
let Constant_List = { "武力", "统率", "智力", "敏捷", "运气" }, Columns_To_Record = Table.CombineColumnsToRecord( Dataset, "nList", Constant_List ), Record_To_nList = Table.TransformColumns( Columns_To_Record, { "nList", each {Record.ToList(_)}, type list } ), fScenario = Table.RenameColumns( Table.SelectRows( Record_To_nList, each [情景] = 1 ), { { "选项", "路径" }, { "nList", "五围" } } ), oScenario = Table.SelectRows( Record_To_nList, each [情景] ˃ 1 ), Previous_Scenarios = Table.AddColumn( oScenario, "上一情景", each [情景] - 1, Int64.Type ), Grouping = Table.Group( Previous_Scenarios, "情景", { "nTable", each _, type table [ 情景 = Int64.Type, 选项 = text, nList = list, 上一情景 = Int64.Type ] } ), Acc_Process = List.Accumulate( Table.Column( Grouping, "nTable" ), fScenario, (x, y)=˃ let InnerJoin = Table.NestedJoin( y, "上一情景", x, "情景", "nTable", JoinKind.Inner ), Expansion = Table.ExpandTableColumn( InnerJoin, "nTable", { "路径", "五围" }, { "上一路径", "上一五围" } ), Add_Path = Table.AddColumn( Expansion, "路径", each Text.Combine( { [上一路径], [选项] }, "|" ), type text ), Add_Summation = Table.AddColumn( Add_Path, "五围", each List.Combine( { [上一五围], [nList] } ), type list ), RemoveCols = Table.SelectColumns( Add_Summation, { "情景", "路径", "五围" } ) in RemoveCols ), TransCol = Table.TransformColumns( Acc_Process, { "五围", (x)=˃ Record.FromList( List.Transform( List.Zip( x ), (y)=˃ List.Sum(y) ), Constant_List ), type record } ), Expand_Records = Table.ExpandRecordColumn( TransCol, "五围", Constant_List ), RemoveCol = Table.RemoveColumns( Expand_Records, "情景" ), DataType = Table.TransformColumnTypes( RemoveCol, List.Zip( { Constant_List, List.Repeat( {Int64.Type}, List.Count(Constant_List) ) } ) ) in DataType
玩到一半我发现攻略里提到如果想让角色得到完美的培养,最后五个选项必须为2,2,1,1,1,并且武力和运气要大于等于50,而统率要大于等于40。对计算出的结果进行筛选,发现要实现完美培养只有一种组合根本没有容错的空间,所以只能开新档重玩了
歪楼问个很基础的问题 合并excel文档查询怎么添加一列 让这一列显示的是这个excel文件的名称呢?(举个例子下载了三个产品的数据指标,每个产品对应的excel文件只能通过文件名判断这是那个产品,但是里面内容没有产品标识,在利用excel的合并查询时,如何添加一列,使得每个产品数据文档前面增加一列作为产品名称,这个产品名称就是产品excel文件的名称)似乎表述的不太清晰
不知道你需要的是不是这种效果:
let
Source = Folder.Files("D:\OneDrive\PQ Fans\Reply\Reply 1\Data Folder"),
Trans_Col =
Table.TransformColumns(
Source,
{
{
"Content",
(x)=>
Table.SelectRows(
Excel.Workbook(
x,
true
),
(y)=> y[Name] = "Tbl"
){0}[Data]
},
{
"Name",
each Text.Split(_, "."){0},
type text
}
}
),
Col_Selection =
Table.SelectColumns(
Trans_Col,
{
"Content",
"Name"
}
),
Expansion =
Table.ExpandTableColumn(
Col_Selection,
"Content",
{
"No"
}
)
in
Expansion