elaj
Hola,
tengo una tabla como esa:
y quiero reemplazar los valores de cadena por números como ese:
«Últimas 4 semanas» = 1
«Hace 2 meses» = 2
«Hace 3 meses» = 3
«Hace 4 meses» = 4
… etc
¿Hay alguna manera de reemplazar con estos múltiples valores en múltiples columnas seleccionadas personalizadas?
Solo encontré soluciones para múltiples valores para una columna … o un valor para múltiples columnas.
Gracias por tus respuestas
Rocco_sprmnt21
si tuviéramos una función replacerAny.ReplaceValue …, podríamos hacerlo todo en un solo paso con la función table.replace.
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("HcYxDQAACAMwL7t52EANwb8NFnp1BolAJjYGdMmvXOlbbtW33W7sHg==", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type text) meta [Serialized.Text = true]) in type table [prima = _t, seconda = _t]),
cols=Table.ColumnNames(Source),
Dict=#table({"old","new"},{{1,"uno"},{3,"tre"},{11,"undici"}}),
replaced=Table.ReplaceValue(
Source,
Dict[old],Dict[new],
replacerAnyReplaceValue,
cols
)
in
replaced
mientras tanto podemos usar esto:
let
rep=(value, old as list , new as list )=>
let
Dict=Record.FromList(List.Transform(new, Text.From), List.Transform(old, Text.From)),
Replacements= Record.FieldOrDefault(Dict,value,value)
in
Replacements
in
rep
Rickmaurinus
Hola,
Reemplazar valores en varias columnas no es la tarea más sencilla. Una forma es usar univot y reemplazar elementos usando List.ReplaceMatchingItems. A continuación, puede hacer referencia a TranslationTable combinando List.ReplaceMatchingItems con List.Zip. Escribo sobre todo esto aquí mismo:
https://gorilla.bi/power-query/replace-values/
¡Espero que ayude!
Almiar
v-juanli-msft
Hola @elaj
Si está descuidado, ¿podría aceptarlo como una solución para cerrar este caso y ayudar a los demás miembros a encontrarlo más rápidamente?
Si no es así, no dudes en hacérmelo saber.
Atentamente
Maggie
Rocco_sprmnt21
si tuviéramos una función replacerAny.ReplaceValue …, podríamos hacerlo todo en un solo paso con la función table.replace.
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("HcYxDQAACAMwL7t52EANwb8NFnp1BolAJjYGdMmvXOlbbtW33W7sHg==", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type text) meta [Serialized.Text = true]) in type table [prima = _t, seconda = _t]),
cols=Table.ColumnNames(Source),
Dict=#table({"old","new"},{{1,"uno"},{3,"tre"},{11,"undici"}}),
replaced=Table.ReplaceValue(
Source,
Dict[old],Dict[new],
replacerAnyReplaceValue,
cols
)
in
replaced
mientras tanto podemos usar esto:
let
rep=(value, old as list , new as list )=>
let
Dict=Record.FromList(List.Transform(new, Text.From), List.Transform(old, Text.From)),
Replacements= Record.FieldOrDefault(Dict,value,value)
in
Replacements
in
rep
Rocco_sprmnt21
En respuesta a Rocco_sprmnt21
Esta versión es una especie de truco que no utiliza iteraciones. Solo usa la función Table.ReplaceValue, utilizando como cuarto parámetro (el lugar de función sustituto) la función Record.FieldOrDefault modificado solo por el orden de sus parámetros
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("HcYxDQAACAMwL7t52EANwb8NFnp1BolAJjYGdMmvXOlbbtW33W7sHg==", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type text) meta [Serialized.Text = true]) in type table [prima = _t, seconda = _t]),
cols=Table.ColumnNames(Source),
Dict=[1="uno",3="tre",11="undici"],
replaced=Table.ReplaceValue(
Source,
Dict,
"UnValoreQualsiasi",
(x,y,z)=>Record.FieldOrDefault(y,x,x),
cols
)
in
replaced
Smauro
Hola @elaj,
He tenido demasiado tiempo libre esta mañana, así que creé una función para reemplazar valores basada en una Tabla de transformación.
Lo bueno es que llama a la tabla de destino una vez y a la tabla de transformación una vez, utilizando una función de reemplazo personalizada dentro de Table.ReplaceValue.
Por demasiado tiempo libre, quiero decir que no solo agregué manejo de errores, sino también documentación.
1) Vas a necesitar una tabla de transformación. Debería ser algo que se vea así:
Los nombres de las columnas son irrelevantes, pero la columna de búsqueda debe ser distinta por razones obvias. Si no se especifica ninguna columna de búsqueda, la primera columna se utiliza como columna de búsqueda y la segunda como reemplazo.
Digamos que nombras esto Transformaciones
2) Agregar la función como una nueva consulta. Usaré una etiqueta de spoiler aquí porque es demasiado larga.
let
TableReplaceValuesFromTableFunction = (table as table, transformationTable as table, optional columns as any, optional specifyTransformationColumns as list, optional missingField as nullable number) as table =>
let
// Buffer Transformation Table to call it only once
BufferedTransformationTable = Table.Buffer(transformationTable),
// Step to add error handling for given table & columns
tryTransformationColumnNames = try
let
temp = Table.ColumnNames(BufferedTransformationTable),
countTargetColumns = List.Count(temp),
countSpecifiedColumns = try List.Count(specifyTransformationColumns) otherwise 0
in
if countTargetColumns < 2 then error [Reason = "", Message = "The transformation table needs to have at least two columns", Detail = [TransformationColumns = temp] ]
else if countSpecifiedColumns = 0 then {temp{0}, temp{1}}
else if countSpecifiedColumns = 2 then
let
l = List.Intersect({specifyTransformationColumns, temp})
in
if List.Count(l) = 2 then l else error [Reason = "", Message = "The transformation table does not contain the 2 specified columns", Detail = [TransformationColumns = temp, SpecifiedColumns = specifyTransformationColumns] ]
else error [Reason = "Error in specified transformation columns", Message = "Please specify exactly 2 columns", Detail = [SpecifiedColumns = specifyTransformationColumns ]],
TransformationColumnNames = tryTransformationColumnNames[Value],
// Define Replacer Function to trick Table.ReplaceValue
CustomReplacer =
(value as any, old as any, new as any) as any =>
let
getvalue = try
Expression.Evaluate(
"tbl{["
& TransformationColumnNames{0}
& " = t]}["
& TransformationColumnNames{1}
& "]",
[ tbl = BufferedTransformationTable, t = value ]
),
newvalue =
if getvalue[HasError] then
if Text.Contains(getvalue[Error][Message], "The key matched more than one row in the table") then error [Reason = "An error occured in the Transformation Table", Message = "More than one replacements were found for the specified value", Detail = [ValueToReplace = value]]
else if (missingField??1) = 0 then
if Text.Contains(getvalue[Error][Message], "The key didn't match any rows in the table") then error [Reason = "An error occured in the Transformation Table", Message = "A replacement cannot be found for the specified value", Detail = [ValueToReplace = value]]
else error getvalue[Error]
else if (missingField??1) = 2 then null
else value
else getvalue[Value]
in
newvalue,
// If table and columns ok, call Table.ReplaceValue
Result = if tryTransformationColumnNames[HasError] then error tryTransformationColumnNames[Error] else Table.ReplaceValue( table, null, null, CustomReplacer, columns??Table.ColumnNames(table) )
in
Result,
// Add documentation
TableReplaceValuesFromTableType = type function (
table as (type table meta [
Documentation.FieldCaption ="Target Table",
Documentation.FieldDescription = "The table to make replacements"
]),
transformationTable as (type table meta [
Documentation.FieldCaption ="Transformation Table",
Documentation.FieldDescription = "The lookup table for replacements"
]),
optional columns as (type any meta [
Documentation.FieldCaption ="Columns",
Documentation.FieldDescription = "The columns in which to replace values"
]),
optional specifyTransformationColumns as (type {text} meta [
Documentation.FieldCaption ="Transformation Columns",
Documentation.FieldDescription = "Columns to check on Transformation Table. If not specified, Column1 and Column2 are used."
]),
optional missingField as MissingField.Type
)
as table meta
[Documentation.Name = "Table.ReplaceValuesFromTable",
Documentation.Description = "Replaces multiple values at once using a lookup table",
Documentation.LongDescription = "Replaces multiple values at once using a lookup table.#(lf)If no columns are specified for the Transformation Table, the first column is used a a lookup and the second as a replacement. If no columns are specified in the Target Table then the default is all columns",
Documentation.Category = "Table",
Documentation.Author = "Spyros Mavroforos",
Documentation.Examples = {[
Description = "Replace values on all columns",
Code = "let
StartingTable =
Table.FromRecords({
[a = 1, b = 2],
[a = 2, b = 2],
[a = 3, b = 4],
[a = 4, b = 5]
}),
transformationTable =
Table.FromRecords({
[check = 1, replace = ""A""],
[check = 2, replace = ""B""],
[check = 3, replace = ""C""],
[check = 4, replace = ""D""]
})
in
Table.ReplaceValuesFromTable(StartingTable, transformationTable)",
Result = "Table.FromRecords({
[a = ""A"", b = ""B""],
[a = ""B"", b = ""B""],
[a = ""C"", b = ""D""],
[a = ""D"", b = 5]
})"
],
[
Description = "Replace values on column 'a'",
Code = "let
StartingTable =
Table.FromRecords({
[a = 1, b = 2],
[a = 2, b = 2],
[a = 3, b = 4],
[a = 4, b = 5]
}),
transformationTable =
Table.FromRecords({
[check = 1, replace = ""A""],
[check = 2, replace = ""B""],
[check = 3, replace = ""C""],
[check = 4, replace = ""D""]
})
in
Table.ReplaceValuesFromTable(StartingTable, transformationTable, {""a""})",
Result = "Table.FromRecords({
[a = ""A"", b = 2],
[a = ""B"", b = 2],
[a = ""C"", b = 3],
[a = ""D"", b = 5]
})"
],
[
Description = "Replace values on column 'b' by using 'Column2' column as lookup and 'Column1' as replacement",
Code = "let
StartingTable =
Table.FromRecords({
[a = ""A"", b = ""B""],
[a = ""B"", b = ""B""],
[a = ""C"", b = ""D""],
[a = ""D"", b = 5]
}),
transformationTable =
Table.FromRecords({
[Column1 = 1, Column2 = ""A""],
[Column1 = 2, Column2 = ""B""],
[Column1 = 3, Column2 = ""C""],
[Column1 = 4, Column2 = ""D""]
})
in
Table.ReplaceValuesFromTable(StartingTable, transformationTable, {""b""}, {""replace"", ""check""}, MissingField.Error)",
Result = "Table.FromRecords({
[a = ""A"", b = 2],
[a = ""B"", b = 2],
[a = ""C"", b = 4],
[a = ""D"", b = error [Reason = """", Message = ""A replacement cannot be found for the specified value"", Detail = [ValueToReplace = 5]]
})"
]}
]
in
Value.ReplaceType(TableReplaceValuesFromTableFunction, TableReplaceValuesFromTableType)
& TransformationColumnNames{0}
& » = t]}[»
& TransformationColumnNames{1}
& «]»,
[ tbl = BufferedTransformationTable, t = value ]
), newvalue = si getvalue[HasError] entonces si Text.Contains (getvalue[Error][Message], «La clave coincidió con más de una fila en la tabla») luego error [Reason = «An error occured in the Transformation Table», Message = «More than one replacements were found for the specified value», Detail = [ValueToReplace = value]]else if (missingField ?? 1) = 0 entonces si Text.Contains (getvalue[Error][Message], «La clave no coincide con ninguna fila de la tabla») y luego aparece el error [Reason = «An error occured in the Transformation Table», Message = «A replacement cannot be found for the specified value», Detail = [ValueToReplace = value]]else error getvalue[Error]
else if (missingField ?? 1) = 2 entonces nulo else valor else getvalue[Value]
in newvalue, // Si la tabla y las columnas están bien, llame a Table.ReplaceValue Result = if tryTransformationColumnNames[HasError] entonces error tryTransformationColumnNames[Error] else Table.ReplaceValue (tabla, nulo, nulo, CustomReplacer, columnas ?? Table.ColumnNames (tabla)) en Resultado, // Agregar documentación TableReplaceValuesFromTableType = tipo función (tabla como (tipo tabla meta [
Documentation.FieldCaption =»Target Table»,
Documentation.FieldDescription = «The table to make replacements»
]), transformTable como (tipo tabla meta [
Documentation.FieldCaption =»Transformation Table»,
Documentation.FieldDescription = «The lookup table for replacements»
]), columnas opcionales como (escriba cualquier meta [
Documentation.FieldCaption =»Columns»,
Documentation.FieldDescription = «The columns in which to replace values»
]), opcional especificarTransformationColumns como (escriba {texto} meta [
Documentation.FieldCaption =»Transformation Columns»,
Documentation.FieldDescription = «Columns to check on Transformation Table. If not specified, Column1 and Column2 are used.»
]), missingField opcional como MissingField.Type) como meta de la tabla
[Documentation.Name = «Table.ReplaceValuesFromTable»,
Documentation.Description = «Replaces multiple values at once using a lookup table»,
Documentation.LongDescription = «Replaces multiple values at once using a lookup table.#(lf)If no columns are specified for the Transformation Table, the first column is used a a lookup and the second as a replacement. If no columns are specified in the Target Table then the default is all columns»,
Documentation.Category = «Table»,
Documentation.Author = «Spyros Mavroforos»,
Documentation.Examples = {[
Description = «Replace values on all columns»,
Code = «let
StartingTable =
Table.FromRecords({
[a = 1, b = 2],
[a = 2, b = 2],
[a = 3, b = 4],
[a = 4, b = 5]
}), transformTable = Table.FromRecords ({
[check = 1, replace = «»A»»],
[check = 2, replace = «»B»»],
[check = 3, replace = «»C»»],
[check = 4, replace = «»D»»]
}) en Table.ReplaceValuesFromTable (StartingTable, transformTable) «, Result =» Table.FromRecords ({
[a = «»A»», b = «»B»»],
[a = «»B»», b = «»B»»],
[a = «»C»», b = «»D»»],
[a = «»D»», b = 5]
}) «],
[
Description = «Replace values on column ‘a'»,
Code = «let
StartingTable =
Table.FromRecords({
[a = 1, b = 2],
[a = 2, b = 2],
[a = 3, b = 4],
[a = 4, b = 5]
}), transformTable = Table.FromRecords ({
[check = 1, replace = «»A»»],
[check = 2, replace = «»B»»],
[check = 3, replace = «»C»»],
[check = 4, replace = «»D»»]
}) en Table.ReplaceValuesFromTable (StartingTable, transformTable, {«» a «»}) «, Result =» Table.FromRecords ({
[a = «»A»», b = 2],
[a = «»B»», b = 2],
[a = «»C»», b = 3],
[a = «»D»», b = 5]
}) «],
[
Description = «Replace values on column ‘b’ by using ‘Column2’ column as lookup and ‘Column1’ as replacement»,
Code = «let
StartingTable =
Table.FromRecords({
[a = «»A»», b = «»B»»],
[a = «»B»», b = «»B»»],
[a = «»C»», b = «»D»»],
[a = «»D»», b = 5]
}), transformTable = Table.FromRecords ({
[Column1 = 1, Column2 = «»A»»],
[Column1 = 2, Column2 = «»B»»],
[Column1 = 3, Column2 = «»C»»],
[Column1 = 4, Column2 = «»D»»]
}) en Table.ReplaceValuesFromTable (StartingTable, transformTable, {«» b «»}, {«» reemplazar «», «» comprobar «»}, MissingField.Error) «, Result =» Table.FromRecords ({
[a = «»A»», b = 2],
[a = «»B»», b = 2],
[a = «»C»», b = 4],
[a = «»D»», b = error [Reason = «»»», Message = «»A replacement cannot be found for the specified value»», Detail = [ValueToReplace = 5]]}) «]}]en Value.ReplaceType (TableReplaceValuesFromTableFunction, TableReplaceValuesFromTableType)
Digamos que nombras la consulta TableReplaceValuesFromTable
3) Cambiando tu tabla real. Suponiendo que Paso anterior es su paso anterior, ahora puede agregar un paso llamando a la función:
= TableReplaceValuesFromTable(PreviousStep, Transformations)
Si necesita especificar las columnas, espero que pueda averiguar cómo.
Mejor,
Spyros
eLjoT
En respuesta a Smauro
¡Excelente trabajo!
¡Eres el tonto!
¡Muchas gracias me ahorras mucho tiempo!
¡Salud!
acu-amersaw
En respuesta a Smauro
¡Guau! eso es increíble, ¡literalmente me salvaste el día!
Gracias por compartir esto.
Ese debería ser el SOLUCIÓN ACEPTADA
Rocco_sprmnt21
Otra forma podría ser esta que usa la función table.replacevalue:
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("HcYxDQAACAMwL7t52EANwb8NFnp1BolAJjYGdMmvXOlbbtW33W7sHg==", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type text) meta [Serialized.Text = true]) in type table [prima = _t, seconda = _t]),
S=Table.ToRows(Source),
cols=Table.ColumnNames(Source),
Dict=[1="uno",3="tre",11="undici",33="tre_e_tre"],
replaced=List.Accumulate(Record.FieldNames(Dict), Source, (s,c)=> Table.ReplaceValue(
s,
c,
Record.Field(Dict,c),
Replacer.ReplaceValue,
cols
))
in
replaced
Aprovecho esta oportunidad para señalar el resultado diferente obtenido con Replace.ReplacerText en lugar de Replace.Replacervalue.
lbendlin
El otro día se sugirió desvincular los datos en pares clave / valor, hacer las sustituciones y luego volver a pivotar. Pensé que era una buena idea.
Rocco_sprmnt21
En respuesta a lbendlin
intenta adaptar esto
let
Dict = [a="apple",b="banana",l="lemon"],
TurnTextToList = Table.AddColumn(Text, "Custom", each Text.Split([Text], " ")),
Replacements = Table.AddColumn(TurnTextToList, "Changed Text Expected", each Text.Combine(List.Transform([Custom],each Record.FieldOrDefault(Dict,_,_))," "))
in
Replacements
usando esta función:
Table.ReplaceValue(
Table.FromRecords({
[a = 1, b = "hello"],
[a = 3, b = "goodbye"]
}),
"goodbye",
"world",
Replacer.ReplaceText,
{"b"}
)
Rocco_sprmnt21
En respuesta a Rocco_sprmnt21
un borrador por el que empezar:
let
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("HcYxDQAACAMwL7t52EANwb8NFnp1BolAJjYGdMmvXOlbbtW33W7sHg==", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type text) meta [Serialized.Text = true]) in type table [prima = _t, seconda = _t]),
S=Table.ToRows(Source),
cols=Table.ColumnNames(Source),
Dict=[1="uno",3="tre",11="undici"],
Replacements = List.Accumulate(S,{},(s,c)=> s&{List.Transform(c,each Record.FieldOrDefault(Dict,_,_))}),
t=Table.FromRows(Replacements,cols)
in
t