You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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里按索引切片列表的更好方法。

报错原因

  1. 函数定义未闭合:Rejoin函数的List.Combine后面缺少右括号,导致后续的IndexIndex等代码被错误解析为该函数的一部分,系统把本该是列表的表达式当成函数处理,直接触发类型转换错误。
  2. 切片逻辑无效:原代码中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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 22:54:35