Forum Discussion
Accumulation, result error / not error
Hello all,
I'd like a bit of help as to how this works, the below returns and error, but if does work in the end, think i know why, and which I have put below, so this returns a list of errors, I think the first logical test returns true / false to the second must return and error ?
let atext = "the cat's bed, the dogs chased the cat, the cats' food, the dog's bone and the cat's milk, the boy had a catapult", old = {"cat", "dog"}, new = {"TIGER", "WOLF"}, removves = {".", ",", ";", "'", "s"}, replace = let split = Splitter.SplitTextByWhitespace()(atext) in List.Transform( split, (x) => List.Accumulate( {0, 1}, x, (s, c) => let test = Text.Remove(s, removves) = old{c} in test ) ) in replaceBut if I then take the test ( see below) true / false , and use it in the following I get the result wanted, not sure why this works any insights as to how this works? does the " if logical' re-set for the second pass of accumulate ? this is all i can think of .
let atext = "the cat's bed, the dogs chased the cat, the cats' food, the dog's bone and the cat's milk, the boy had a catapult", old = {"cat", "dog"}, new = {"TIGER", "WOLF"}, removves = {".", ",", ";", "'", "s"}, replace = let split = Splitter.SplitTextByWhitespace()(atext) in List.Transform( split, (x) => List.Accumulate( {0, 1}, x, (s, c) => let test = Text.Remove(s, removves) = old{c} in if test then Text.Replace(s, old{c}, new{c}) else s ) ), result = Text.Combine(replace, " ") in result
Ignore my previous reply, i was having a dumb moment.
Step by Step this is what your top code is doing and its issues:- Splitter.SplitTextByWhitespace() splits the sentence into a list of words.
- List.Transform processes each word x with List.Accumulate({0,1}, x, ...).
- For each word, it accumulates over indices {0,1} :
- c=0: Text.Remove(s, removves) strips . , , , ; , ' , s from the word, then compares the result to old{0} ("cat"), producing a boolean (true/false). This boolean becomes the new accumulator value s .
- c=1: it then tries Text.Remove(s, removves) again — but s is now a boolean, not text. Text.Remove requires a text value, so this step throws a type-conversion error ("We cannot convert the value True/False to type Text").
Other issues:
- new = {"TIGER", "WOLF"} is defined but never used. There's no actual replacement happening, despite the variable name replace implying substitution.
- removves strips the letter "s" from anywhere in the word, not just trailing plural "s". This would mangle words like "was" → "wa".
- Because old{1} ("dog") is never checked in a way that survives (the accumulator overwrites itself with a boolean after the first pass), even if the type error didn't occur, the "dog" comparison logic is broken.
Net result:
This query will fail at evaluation time with a type error on the second accumulation step for every word, it does not successfully identify or replace "cat"/"dog" occurrences with "TIGER"/"WOLF".
Comparing that to your second code, this version fixes the type bug and actually does the replacement. Key differences:- Accumulator now stays text-typed throughout
- test = Text.Remove(s, removves) = old{c} still computes the boolean, but it's only used inside an if, not stored as the accumulator.
- if test then Text.Replace(s, old{c}, new{c}) else s the accumulator s always remains a string: either the replaced text or the unchanged original. This avoids the previous "boolean fed into Text.Remove" type error.
- new is now actually used
- When the stripped word matches old{c}, Text.Replace swaps the original word text (s , punctuation/apostrophes intact) for new{c} e.g., "cat's" → since Text.Remove("cat's", removves) = "cat" matches old{0}, it does Text.Replace("cat's", "cat", "TIGER") → "TIGERs'" ... actually let's check: Text.Replace replaces the substring "cat" inside "cat's", giving "TIGER's". Punctuation around it is preserved, not stripped.
- Both indices now meaningfully checked
- c=0 checks against "cat"/"TIGER", c=1 checks against "dog"/"WOLF", each independently applied to whatever s currently is, so a word can be tested/replaced for cat, then (unchanged, since it won't match "dog") passed through for the dog check.
- Added Text.Combine(replace, " ")
- Rejoins the transformed word list into a single string, so the result is readable text, whereas the original returned a list of words with no recombination.
Problems I still see:
- Stripping "s" anywhere (not just trailing) still risks false matches (e.g., "dogs" → "dog" correctly, but any word containing an internal "s" gets mangled before comparison, though the replacement itself uses the original s , so display text is safer than before).
- Words like "cats'" → stripped to "cat" → matches → Text.Replace("cats'", "cat", "TIGER") → "TIGERs'" (plural/apostrophe artifacts remain, since only the substring "cat" is replaced, not the whole cleaned token).
- Whitespace based splitting means original punctuation attached to words is retained in s, so replacements produce oddly suffixed results like "TIGER's", "WOLFs", "TIGERs'".
4 Replies
- Dicken
Post Prodigy
well that's pretty thorough. thanks for taking the time.
- krishnakanth240
Super User
Hi Dicken
You can use List.PositionOf / List.Transform with a lookup
let
atext = "the cat's bed, the dogs chased the cat, the cats' food, the dog's bone and the cat's milk, the boy had a catapult",
old = {"cat", "dog"},
new = {"TIGER", "WOLF"},
removves = {".", ",", ";", "'", "s"},
split = Splitter.SplitTextByWhitespace()(atext),
replace = List.Transform(
split,
(x) =>
let
clean = Text.Remove(x, removves),
pos = List.PositionOf(old, clean)
in
if pos <> -1 then new{pos} else x),
result = Text.Combine(replace, " ")
in
result
- Dicken
Post Prodigy
that was not the question, the question related to why if you return 'test' it returns and error,
i did lay this all out.
- RossEdwardsRio
Helper I
Ignore my previous reply, i was having a dumb moment.
Step by Step this is what your top code is doing and its issues:- Splitter.SplitTextByWhitespace() splits the sentence into a list of words.
- List.Transform processes each word x with List.Accumulate({0,1}, x, ...).
- For each word, it accumulates over indices {0,1} :
- c=0: Text.Remove(s, removves) strips . , , , ; , ' , s from the word, then compares the result to old{0} ("cat"), producing a boolean (true/false). This boolean becomes the new accumulator value s .
- c=1: it then tries Text.Remove(s, removves) again — but s is now a boolean, not text. Text.Remove requires a text value, so this step throws a type-conversion error ("We cannot convert the value True/False to type Text").
Other issues:
- new = {"TIGER", "WOLF"} is defined but never used. There's no actual replacement happening, despite the variable name replace implying substitution.
- removves strips the letter "s" from anywhere in the word, not just trailing plural "s". This would mangle words like "was" → "wa".
- Because old{1} ("dog") is never checked in a way that survives (the accumulator overwrites itself with a boolean after the first pass), even if the type error didn't occur, the "dog" comparison logic is broken.
Net result:
This query will fail at evaluation time with a type error on the second accumulation step for every word, it does not successfully identify or replace "cat"/"dog" occurrences with "TIGER"/"WOLF".
Comparing that to your second code, this version fixes the type bug and actually does the replacement. Key differences:- Accumulator now stays text-typed throughout
- test = Text.Remove(s, removves) = old{c} still computes the boolean, but it's only used inside an if, not stored as the accumulator.
- if test then Text.Replace(s, old{c}, new{c}) else s the accumulator s always remains a string: either the replaced text or the unchanged original. This avoids the previous "boolean fed into Text.Remove" type error.
- new is now actually used
- When the stripped word matches old{c}, Text.Replace swaps the original word text (s , punctuation/apostrophes intact) for new{c} e.g., "cat's" → since Text.Remove("cat's", removves) = "cat" matches old{0}, it does Text.Replace("cat's", "cat", "TIGER") → "TIGERs'" ... actually let's check: Text.Replace replaces the substring "cat" inside "cat's", giving "TIGER's". Punctuation around it is preserved, not stripped.
- Both indices now meaningfully checked
- c=0 checks against "cat"/"TIGER", c=1 checks against "dog"/"WOLF", each independently applied to whatever s currently is, so a word can be tested/replaced for cat, then (unchanged, since it won't match "dog") passed through for the dog check.
- Added Text.Combine(replace, " ")
- Rejoins the transformed word list into a single string, so the result is readable text, whereas the original returned a list of words with no recombination.
Problems I still see:
- Stripping "s" anywhere (not just trailing) still risks false matches (e.g., "dogs" → "dog" correctly, but any word containing an internal "s" gets mangled before comparison, though the replacement itself uses the original s , so display text is safer than before).
- Words like "cats'" → stripped to "cat" → matches → Text.Replace("cats'", "cat", "TIGER") → "TIGERs'" (plural/apostrophe artifacts remain, since only the substring "cat" is replaced, not the whole cleaned token).
- Whitespace based splitting means original punctuation attached to words is retained in s, so replacements produce oddly suffixed results like "TIGER's", "WOLFs", "TIGERs'".