На самом деле в ней миллионы строк и очень много числовых столбцов.
Мне бы сделать формулой такую математику: если в коронке 1 treu, то в данной строке в каждой из колонок (колонок много, т.е. нельзя перечислять их вручную) число умножить на 10, а если fakse - на 20.
Вот вроде просто должно быть, но я совсем неумеха пока. Помогите, плиз.
buchlotnik, я пытаюсь детально разобрать Ваше решение. У меня пока получается так:
Шаг 1: Таблица преобразуется в записи: tbl = Table.ToRecords(from), Шаг 2: Указывается применение к записям функции g: trnsf= List.Transform(tbl,g), Шаг 3: Производится проверка для каждой записи x [#"TRUE/FALSE"]: g=(x)=> if x[#"TRUE/FALSE"]=true then f(x,10) else f(x,20), и в зависимости от результата с параметрами переходим дальше: Шаг 4: Для каждой записи вызывается разный f: then f(x,10) else f(x,20): f=(x,y)=>List.Accumulate(lst,x,(s,c)=>Record.TransformFields(s,{c,(x)=>x*y})):
И вот возник вопрос... от откуда берётся x и что это?
Kirill Gureev, если не сложно то после сравнения на вашем большом объеме скажите какая разница в скорости? Мое мнение вариант от Михаила с красной пробиркой будет быстрее.
let
Source = Excel.CurrentWorkbook(){[Name="Таблица1"]}[Content],
f10 = (x) => if x is logical then x else 10 * x,
f20 = (x) => if x is logical then x else 20 * x,
methods = List.Transform(Source[#"TRUE/FALSE"], each if _ then f10 else f20),
zip = List.Zip({methods, Table.ToRows(Source)}),
calc = List.Transform(zip, (pair) => List.Transform(pair{1}, pair{0})),
toTable = Table.FromRows(calc, Table.ColumnNames(Source))
in
toTable
На честных 255 столбцах (первый с именем "TRUE/FALSE" и значениями true/false) и 10000 строк. Updated. Чуть похимичил buchlotnik 99 секунд; у меня 22 секунды19,5 секунд
это функция двух переменных - x и y - которая проходит по списку lst (первый аргумент List.Accumulate и по совместительству список всех изменяемых столбцов) и совершает преобразование с x (напоминаю, мы туда передаем запись); суть преобразования - изменить поле записи (Record.TransformFields) с текущего на текущее*y
это конечно не моё дело, но может стоит справку по PQ почитать? там интересно...
Всё-таки неисповедимы пути оптимизации в PQ. Пытался что-то сварганить с List.Generate - всё равно запрос выполнялся процентов на 60 дольше, чем у Андрей VG. Сделал элементарно - всё летает. Чудеса-чудеса - небывальщина...
Вариант без сортировки строк:
Код
let
Source = data,
cols = List.Buffer(List.Skip(Table.ColumnNames(Source))),
final = Table.TransformColumns(
Table.SelectRows(Source, each [#"TRUE/FALSE"]),
List.Transform(cols, (x) => {x, each _ * 10})
)
& Table.TransformColumns(
Table.SelectRows(Source, each not [#"TRUE/FALSE"]),
List.Transform(cols, (x) => {x, each _ * 20})
)
in
final
Чуть медленнее - с сортировкой:
Код
let
Source = data,
i = Table.AddIndexColumn(Source, "i"),
cols = List.Buffer(List.RemoveItems(Table.ColumnNames(i), {"TRUE/FALSE", "i"})),
transform = Table.TransformColumns(
Table.SelectRows(i, each [#"TRUE/FALSE"]),
List.Transform(cols, (x) => {x, each _ * 10})
)
& Table.TransformColumns(
Table.SelectRows(i, each not [#"TRUE/FALSE"]),
List.Transform(cols, (x) => {x, each _ * 20})
),
final = Table.RemoveColumns(Table.Sort(transform, {"i", 0}), "i")
in
final
Ой, и не говорите.... Большое спасибо, Алексей! Ваш вариант - 10 секунд. Updated. Для сравнения - код на VBA выполняется 2,6 секунды.
Скрытый текст
Код
Public Sub TestVbaSpeed()
Dim pLO As ListObject, vData, i As Long, t As Single
Dim vMult As Double, k As Long, outSheet As Worksheet
Dim outRange As Range
t = Timer
Set pLO = ThisWorkbook.Worksheets("Лист1").ListObjects(1)
vData = pLO.Range.Value
For i = 2 To UBound(vData, 1)
vMult = IIf(vData(i, 1), 10#, 20#)
For k = 2 To UBound(vData, 2)
vData(i, k) = vMult * vData(i, k)
Next
Next
Set outSheet = ThisWorkbook.Worksheets.Add
Set outRange = outSheet.Range("A1").Resize(UBound(vData, 1), UBound(vData, 2))
outRange.Value = vData
outSheet.ListObjects.Add xlSrcRange, outRange, , xlYes
MsgBox Timer - t
End Sub