Страницы: 1
RSS
Распределение веса брутто пропорционально весу нетто
 
Добрый день!

На работе зачастую приходят файлы с весом брутто и нетто товара (во вложении пример). При этом, напротив некоторых строк с весом нетто стоят объединённые строки с общим весом брутто. Приходится распределять этот общий вес брутто для каждой строки пропорционально весу нетто. Делаю это при помощи формулы. В столбце "С" файла  показан результат распределения и формула, которой пользуюсь. Но приходится писать эту формулу для каждого блока с объединённым весом брутто, что занимает довольно много времени.

Можно ли как-то автоматизировать данный процесс?

Отмечу такой нюанс: после протягивания формулы результат зачастую бывает больше или меньше на 0,001-0,003. Приходится в одной ячейке с распределенным весом брутто прибавлять или отнимать 0,001 - 0,003, чтобы получилось равное число (в прилагаемом файле это ячейки C26 и С45) . Желательно, этот нюанс учесть при автоматизации.
Изменено: Aleksey1990 - 08.08.2026 15:39:01
 
Добрый день!
Если версия экселя новая, попробуйте в С2:
(результат вставил в столбец Е)
Код
=LET(r;СТРОКА();s;ПРОСМОТР(2;1/($B$2:B2<>"");СТРОКА($B$2:B2));e;ЕСЛИОШИБКА(r+ПОИСКПОЗ(ИСТИНА;ИНДЕКС($B3:$B$45<>"";0);0)-1;45);g;ИНДЕКС($B:$B;s);t;СУММ(ИНДЕКС($A:$A;s):ИНДЕКС($A:$A;e));ЕСЛИ(r=e;ЕСЛИ(r=s;ОКРУГЛ(g;3);ОКРУГЛ(g-СУММ(ИНДЕКС($C:$C;s):ИНДЕКС($C:$C;r-1));3));ОКРУГЛ(A2/t*g;3)))
Изменено: DAB - 08.08.2026 21:41:49
 
Вариант макроса (ЮДФ)
Код
Option Explicit
Option Base 1

Function БруттоРаспр(НеттоБрутто As Range)
    Dim T1(), T2(), NSum As Double, BSum As Double
    Dim N As Long, K As Long, L As Long, R1s() As Long, R2s() As Long
    '
    N = НеттоБрутто.Rows.Count
    With WorksheetFunction
        T1 = .Transpose(НеттоБрутто.Value)
        ReDim Preserve T1(2, N + 1)
        T1 = .Transpose(T1)
    End With
    ReDim T2(N, 1), R1s(0 To 0), R2s(0 To 0)
    For K = 1 To N
        If Len(T1(K, 2)) Then
            NextValue(R1s) = K
            If Len(T1(K + 1, 2)) Then NextValue(R2s) = K
        ElseIf Len(T1(K + 1, 2)) Then
            NextValue(R2s) = K
        End If
    Next
    NextValue(R2s) = N
    For L = 1 To UBound(R1s)
        K = R1s(L)
        BSum = T1(K, 2)
        If R2s(L) = K Then
            T2(K, 1) = BSum
        Else
            NSum = 0
            For K = K To R2s(L)
                NSum = NSum + T1(K, 1)
            Next
            For K = R1s(L) To R2s(L)
                T2(K, 1) = T1(K, 1) / NSum * BSum
            Next
        End If
    Next
    БруттоРаспр = T2
End Function

Property Let NextValue(Values, NewValue)
    ReDim Preserve Values(0 To UBound(Values) + 1)
    Values(UBound(Values)) = NewValue
End Property 
Aleksey1990, вот чего я не понял - зачем округлять каждую поззицию ?
Установить в колонке "Число десятичных знаков" сколько надо и всё !
Кто-то, глядя в монитор, проверять суммы на калькуляторе будет ?
 
Цитата
написал:
Добрый день!Если версия экселя новая, попробуйте в С2:(результат вставил в столбец Е)
Спасибо!

Отличное решение! Буду пользоваться!
 
Цитата
написал:
Добрый день!Если версия экселя новая, попробуйте в С2:(результат вставил в столбец Е)
И все таки не совсем рабочий вариант.

Для теста в столбцы А и B вставил данные из другой поставки (на разные поставки могут быть разные веса и количество строк). Вашу формулу вставил в C и протянул донизу. Все получилось хорошо, кроме блока с нижним весом брутто (2535 кг.). Почему-то распределённая сумма получилась больше - 2569,33 кг.

Результаты прилагаю. Может что-то не так делаю?
 
Aleksey1990, Попробуйте в формуле этот блок:
ЕСЛИОШИБКА(r+ПОИСКПОЗ(ИСТИНА;ИНДЕКС($B3:$B$45<>"";0);0)-1;45)
заменить на
ЕСЛИОШИБКА(r+ПОИСКПОЗ(ИСТИНА;ИНДЕКС($B3:ИНДЕКС(B:B;СЧЁТЗ(A:A))<>"";0);0)-1;СЧЁТЗ(A:A))
 
Цитата
написал:
ЕСЛИОШИБКА(r+ПОИСКПОЗ(ИСТИНА;ИНДЕКС($B3:ИНДЕКС(B:B;СЧЁТЗ(A:A))<>"";0);0)-1;СЧЁТЗ(A:A))
Получилось. Работает как надо.

Благодарю Вас!
 
Цитата
Aleksey1990:    прибавлять или отнимать 0,001 - 0,003, чтобы получилось равное число (в прилагаемом файле это ячейки C26 и С45)
Aleksey1990, в какой ячейке "блока" имеет значение?
сделал в первой ячейке "блока":
д.массив
 
ОФФ (по понедельникам)  :)

Эксель у меня старенький  :( , LET() функции - нету, а захотелось узнать как работает формула Павла W.
Разложил формулу по "полочкам" - именованным формулам.

Но ... как работает, так всё равно не понял  :( .
 
Цитата
захотелось узнать как работает формула Павла W ... не понял
))
Цитата
поскольку фунции ПОСЛЕД() у меня нет,
пришлось сочинить UDF Натуральные()
С.М., вместо ПОСЛЕД() можно "прикрутить" функцию СТРОКА()
подправил имена в диспетчере имен
Но..., для старых версий я бы не заморачивался и сделал бы с доп столбцами -  и проще, и наглядней, и менее ресурсоёмко,... а некоторые столбцы можно использовать и в других вычислениях (например номер паллета)
см Лист1 (2)

пс: основная логика в Лист1 (2) та же
 
Цитата
ПавелW написал:
С.М. , вместо ПОСЛЕД() можно "прикрутить" функцию СТРОКА()
ПавелW, в этом случае формула должна пересчитываться в каждой ячейке.
А предыдущая версия (с ПОСЛЕД()) возвращала и вставляла на лист - массив, а это - быстрее.
Изменено: С.М. - 11.08.2026 20:53:56
 
С.М., еще раз,   результат этих формул:
=ПОСЛЕД(ЧСТРОК(_а))
=Натуральные(ЧСТРОК(_а))
=СТРОКА(_а)-СТРОКА($A$1)
один и тот же массив
Если вас смутила эта формула:
=ИНДЕКС(ж_;СТРОКА(C1))
то она лишь последовательно извлекает значения из вычисленного один раз массива
вы можете так же как и у себя CSE:
=ж_
 
Цитата
ПавелW написал:
С.М. , еще раз
Аааа, я забыл  :(  , ну конечно, СТРОКА(_а)-СТРОКА($A$1) - массив.
Цитата
ПавелW написал:
Если вас смутила эта формула
Да.
Извлекает то 1 раз, но на лист вставляет много-много раз.
Формула пересчитывается в каждой ячейке.
Цитата
ПавелW написал:
вы можете так же как и у себя CSE:
=ж_
Вот:
Изменено: С.М. - 13.08.2026 10:40:02
 
Цитата
Формула пересчитывается в каждой ячейке.
С.М., не должна)- в диспетчере имён нет летучих функций в именах, и ссылки там абсолютные
поэтому
Цитата
она лишь последовательно извлекает значения из вычисленного один раз массива
 
Эксперимент:
Код
Option Explicit

Rem http://excelvba.ru/articles/WinAPI
#If Win64 Then
    #If VBA7 Then    ' Windows x64, Office 2010
        Declare PtrSafe Function GetTickCount Lib "Kernel32" () As LongLong
    #Else    ' Windows x64,Office 2003-2007
        Declare Function GetTickCount Lib "Kernel32" () As LongLong
    #End If
#Else
    #If VBA7 Then    ' Windows x86, Office 2010
        Declare PtrSafe Function GetTickCount Lib "Kernel32" () As Long
    #Else    ' Windows x86, Office 2003-2007
        Declare Function GetTickCount Lib "Kernel32" () As Long
    #End If
#End If
Rem Надеюсь, что GetTickCount (число миллисекунд) отработает и в новых версиях Эксель

Sub Test1()
    Dim Rng1 As Range, Rng2 As Range, Rng3 As Range
    Dim ICnt1 As Long, ICnt2 As Long, ICnt3 As Long, I As Long
    Dim T0, T1, T2, T3
    Set Rng1 = Sheet1.[C2:C145] ' ИНДЕКС(ж_;СТРОКА(C1))
    Set Rng2 = Sheet1.[E2:E145] ' ж_
    Set Rng3 = Sheet1.[G2:G145] ' C2=E2 (просто так, для сравнения)
    ICnt1 = 1
    ICnt2 = 100
    ICnt3 = 1000
    Application.Calculation = xlCalculationManual
    T0 = GetTickCount
        For I = 1 To ICnt1
            Rng1.Calculate
        Next
    T1 = GetTickCount
        For I = 1 To ICnt2
            Rng2.Calculate
        Next
    T2 = GetTickCount
        For I = 1 To ICnt3
            Rng3.Calculate
        Next
    T3 = GetTickCount
    Application.Calculation = xlCalculationAutomatic
    Debug.Print "====Test1====="
    Debug.Print "DT1 = " & T1 - T0 & " ms"
    Debug.Print "DT2 = " & T2 - T1 & " ms"
    Debug.Print "DT3 = " & T3 - T2 & " ms"
    Debug.Print "DT1/ICnt1 = " & Format((T1 - T0) / ICnt1, "0.00")
    Debug.Print "DT2/ICnt2 = " & Format((T2 - T1) / ICnt2, "0.00")
    Debug.Print "DT3/ICnt3 = " & Format((T3 - T2) / ICnt3, "0.00")
End Sub
Мой результат:
Код
====Test1=====
DT1 = 1484 ms
DT2 = 1375 ms
DT3 = 1141 ms
DT1/ICnt1 = 1484,00
DT2/ICnt2 = 13,75
DT3/ICnt3 = 1,14
В 100 ! раз
 
С.М., безусловно  извлечение значения в каждой ячейке добавит времени ...ровно на столько - сколько ячеек) .Здесь вопрос скорее к скорости извлечения
Потом работать с массивом в таком виде - на любителя. Есть определенные неудобства например: переопределять размер массива, умные таблицы не дружат с массивами...
 
Aleksey1990,
можно решить с помощью PQ

Код
let
    from = Excel.CurrentWorkbook(){[Name="Исходник"]}[Content],
    f = (x)=>
        [val = List.First(x[#"Брутто (нераспределённый)"]),
         sum = List.Sum(x[Нетто]),
         tolst = Table.ToList(x, (y)=>{y{0}, y{1}, y{0}/sum*val})][tolst],
    gr = Table.Group(from, "Брутто (нераспределённый)", {"tmp", f}, GroupKind.Local, (s,c)=> Number.From(c<>null) ),
    cmb = List.Combine(gr[tmp]),
    frlst = Table.FromList(cmb, (x)=>x, type table [Нетто = number, #"Брутто (нераспределённый)" = number, #"Брутто (распределённый)" = number])
in
   frlst
Шлюхогон42
 
Цитата
ПавелW написал #16:
Ok. End ОФФ.
Изменено: С.М. - 13.08.2026 20:30:41
Страницы: 1
Читают тему
Наверх