需求
在百度知道上看到一位网友提问,如何把下面的表格变成标准的数据记录表:
地区 | 姓名 | 数值 | 姓名 | 数值 | 姓名 | 数值 |
---|---|---|---|---|---|---|
北京 | 张三 | 45 | 李四 | 89 | 王五 | 16 |
北京 | 赵毅 | 18 | ||||
上海 | 刘柳 | 89 | 苗布 | 25 | ||
上海 | 白桥 | 65 |
分析
这个表格要实现的结果是下面这样子:
地区 | 姓名 | 数值 |
---|---|---|
北京 | 张三 | 45 |
北京 | 赵毅 | 18 |
上海 | 刘柳 | 89 |
上海 | 白桥 | 65 |
北京 | 李四 | 89 |
上海 | 苗布 | 25 |
北京 | 王五 | 16 |
所以原始数据的第一列【地区】是数据记录的一个字段,后面的每一列【姓名】和紧跟其后的【数值】列加上这个【地区】列构成一组完整的数据记录。
示例中有三组数据记录要合并成一组完整的数据记录。
但推而广之,可能有N组数据记录要处理。
怎么把处理方式通用化?
方法一:分组结合index
let
源 = Excel.CurrentWorkbook(){[Name="表1"]}[Content],
自定义1 = Table.ColumnNames(源),
转换为表 = Table.FromList(自定义1, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
已添加索引 = Table.AddIndexColumn(转换为表, "索引", 0, 1),
已添加自定义 = Table.AddColumn(已添加索引, "自定义", each Number.IntegerDivide([索引]+(n-1),n)),
分组的行 = Table.Group(已添加自定义, {"自定义"}, {{"data", each _, type table [Column1=text, 索引=number, 自定义=number]}}),
已添加自定义1 = Table.AddColumn(分组的行, "test", each Table.SelectColumns(源,List.Combine({{List.First(Table.ColumnNames(源))},[data][Column1]}))),
删除的错误 = Table.RemoveRowsWithErrors(已添加自定义1, {"test"}),
删除的其他列 = Table.SelectColumns(删除的错误,{"test"}),
自定义2 = Table.TransformColumns(删除的其他列,{"test",Table.DemoteHeaders}),
#"展开的“test”" = Table.ExpandTableColumn(自定义2, "test", Table.ColumnNames(自定义2[test]{0})),
提升的标题 = Table.PromoteHeaders(#"展开的“test”", [PromoteAllScalars=true]),
更改的类型 = Table.TransformColumnTypes(提升的标题,{{"数值", Int64.Type}}),
删除的错误1 = Table.RemoveRowsWithErrors(更改的类型, {"数值"}),
筛选的行 = Table.SelectRows(删除的错误1, each ([数值] <> null))
in
筛选的行
方法二:逆透视结合index
let
源 = Excel.CurrentWorkbook(){[Name="表1"]}[Content],
逆透视的列 = Table.UnpivotOtherColumns(源, {List.First(Table.ColumnNames(源))}, "属性", "值"),
自定义1 = Table.TransformColumns(逆透视的列,{"属性", each Text.Remove(_,{"1".."9"})}),
已添加索引 = Table.AddIndexColumn(自定义1, "索引", 0, 1),
已添加自定义 = Table.AddColumn(已添加索引, "自定义", each Number.IntegerDivide([索引],n)),
分组的行 = Table.Group(已添加自定义, {List.First(Table.ColumnNames(源)), "自定义"}, {{"计数", each Table.RowCount(_), type number}, {"data", each _, type table }}),
自定义2 = Table.TransformColumns(分组的行,{"data", each Table.PromoteHeaders(Table.Transpose(Table.SelectColumns(_,{"属性","值"})))}),
#"展开的“data”" = Table.ExpandTableColumn(自定义2, "data", Table.ColumnNames(自定义2[data]{0})),
删除的其他列 = Table.SelectColumns(#"展开的“data”", List.FirstN(Table.ColumnNames(源),n+1))
in
删除的其他列
总结
两种方法都要求第一列要和后面的其他列分别组成完整的数据记录。
用了参数【n】,n的值取等于每一组完整的数据记录所占的列数-1。比如上面的表格,【姓名】和【数值】两列加上【地区】列构成一个完整的数据记录组,那么n=3-1=2。我提供的附件中,【姓名】、【年级】和【数值】加上【地区】列,构成一个完整的数据记录组,那么n=4-1=3。
为了通用化,涉及列引用的地方,我都用了动态引用,或者直接将表格标题降下来(Table.DemoteHeaders)。
这两种方法都可以改造为一个自定义函数,其参数有两个,一个是n,一个是作为数据源的表格。