Power Query M代码List Slicing遇列表转函数运行时错误求助
问题
在Power Query里写了段M代码,想用自定义函数实现列表切片,结果运行时报错:
Expression.Error: We cannot convert a value of type List to type Function.
Details:
Value=[List]
Type=[Type]
用到的M代码:
let BodyText = Table1_2, splitfunc = SMTSplit, SplitLines = Text.Split(BodyText, "#(lf)"), CleanedLines = List.Transform(SplitLines, each Text.Remove(_, {":",";"," "})), SplitCriteria = List.Transform(CleanedLines, each splitfunc(_)), CriteriaIndexes = List.PositionOf(SplitCriteria, true,Occurrence.All), Rejoin = (LineList as list) as text => List.Combine(List.Transform(LineList, each _ + "#(lf)"), IndexIndex = List.Positions(CriteriaIndexes), MaxIndexIndex = List.Max(IndexIndex), MaxLineIndex = List.Max(List.Positions(SplitLines)), BodySplits = List.Transform( IndexIndex, each if _ < MaxIndexIndex then List.Range(CriteriaIndexes(_), CriteriaIndexes(_)- CriteriaIndexes(_)) else List.Range(CriteriaIndexes(_), MaxLineIndex - CriteriaIndexes(_)) ) in BodySplits
补充信息:Table1_2是带换行的字符串数据:
SMT6 Sometexthere TMs Header1 kkagorqr an fgaklgas55SMT3 dall WorkingonSMT6
自定义函数SMTSplit代码:
SMTSplit = (TestText as text) => let split = Text.Length(TestText) < 6 and Text.Contains(TestText, "SMT") in split
需要找出报错原因,以及Power Query里按索引切片列表的更好方法。
报错原因
- 函数定义未闭合:
Rejoin函数的List.Combine后面缺少右括号,导致后续的IndexIndex等代码被错误解析为该函数的一部分,系统把本该是列表的表达式当成函数处理,直接触发类型转换错误。 - 切片逻辑无效:原代码中
List.Range的长度参数写为CriteriaIndexes(_)- CriteriaIndexes(_),结果是0,会返回空列表,完全达不到切片的目的。正确的长度应该是下一个分割点索引减去当前索引,最后一段则是总列表长度减去当前索引。
修正后的代码
先移除未使用的Rejoin函数(或补全其定义),再修正List.Range的参数逻辑:
let BodyText = Table1_2, splitfunc = SMTSplit, SplitLines = Text.Split(BodyText, "#(lf)"), CleanedLines = List.Transform(SplitLines, each Text.Remove(_, {":",";"," "})), SplitCriteria = List.Transform(CleanedLines, each splitfunc(_)), CriteriaIndexes = List.PositionOf(SplitCriteria, true, Occurrence.All), IndexIndex = List.Positions(CriteriaIndexes), MaxIndexIndex = List.Max(IndexIndex), MaxLineIndex = List.Max(List.Positions(SplitLines)), BodySplits = List.Transform(IndexIndex, each let currentIdx = CriteriaIndexes(_) in if _ < MaxIndexIndex then List.Range(SplitLines, currentIdx, CriteriaIndexes(_ + 1) - currentIdx) else List.Range(SplitLines, currentIdx, MaxLineIndex - currentIdx + 1) ) in BodySplits
按索引切片列表的更优方法
方法1:用List.Generate迭代分割点
代码简洁逻辑清晰,适合纯列表分割场景:
let BodyText = Table1_2, SplitLines = Text.Split(BodyText, "#(lf)"), CleanedLines = List.Transform(SplitLines, each Text.Remove(_, {":",";"," "})), // 直接内联判断逻辑,无需单独自定义函数(复用率低时更高效) SplitCriteria = List.Transform(CleanedLines, each Text.Length(_) < 6 and Text.Contains(_, "SMT")), CriteriaIndexes = List.PositionOf(SplitCriteria, true, Occurrence.All), // 添加列表末尾索引,统一处理最后一段 SplitPoints = CriteriaIndexes & {List.Count(SplitLines)}, // 迭代生成切片 BodySplits = List.Generate( () => [idx = 0], each [idx] < List.Count(SplitPoints) - 1, each [idx = [idx] + 1], each List.Range(SplitLines, SplitPoints{[idx]}, SplitPoints{[idx]+1} - SplitPoints{[idx]}) ) in BodySplits
方法2:转表格分组处理
适合需要对切片内容做结构化操作的场景,灵活性更高:
let BodyText = Table1_2, SplitLines = Text.Split(BodyText, "#(lf)"), // 转表格并添加行索引 LineTable = Table.FromList(SplitLines, Splitter.SplitByNothing(), {"Line"}), LineTableWithIndex = Table.AddIndexColumn(LineTable, "Index", 0, 1), // 添加清理文本和分割点标识 LineTableWithFlags = Table.AddColumn(LineTableWithIndex, "CleanedLine", each Text.Remove([Line], {":",";"," "})), LineTableWithFlags = Table.AddColumn(LineTableWithFlags, "IsSplitPoint", each Text.Length([CleanedLine]) < 6 and Text.Contains([CleanedLine], "SMT")), // 生成分组ID:每遇到一个分割点,分组ID递增 LineTableWithGroups = Table.AddColumn(LineTableWithFlags, "GroupID", let SplitIndexes = List.PositionOf(LineTableWithFlags[IsSplitPoint], true, Occurrence.All) in each List.Count(List.Select(SplitIndexes, (x) => x <= [Index])) ), // 按分组ID提取行内容 GroupedTable = Table.Group(LineTableWithGroups, {"GroupID"}, {{"Lines", each [Line]}}), BodySplits = GroupedTable[Lines] in BodySplits
内容的提问来源于stack exchange,提问作者Isaacnfairplay
相关产品推荐
相关产品推荐

