Выбрать дату в календареВыбрать дату в календаре

Страницы: 1 2 3 4 5 6 7 8 9 10 11 ... 300 След.
Задача о рюкзаке в квадрате или нет
 
Увеличил случайный поиск при определении лучшей строки.
Код
Option Explicit
Private aSour As Variant
Private aIndx As Variant
Private aComb As Variant
Private dic As Dictionary

Private Sub CommandButton2_Click()
    Unload Me
End Sub

Private Sub TextBox1_Change()
    ChangeAddress
End Sub

Private Sub TextBox2_Change()
    ChangeAddress
End Sub

Private Sub TextBox4_Change()
    ChangeAddress
End Sub

Private Sub ChangeAddress()
    Dim rSour As Range
    On Error Resume Next
    Set rSour = Лист1.Range(Me.TextBox4.Value).Resize(TextBox2.Value, TextBox1.Value)
    If Err = 0 Then
        LabelAddress.Caption = rSour.Address(0, 0, xlA1)
        aSour = rSour.Value
        aSour = TransformSourceArray(aSour)
    End If
    On Error GoTo 0
End Sub

Private Function TransformSourceArray(aSour As Variant) As Variant
    Dim arr As Variant, brr As Variant
    ReDim arr(LBound(aSour, 1) To UBound(aSour, 1))
    ReDim brr(LBound(aSour, 2) To UBound(aSour, 2)) As Boolean
    
    Dim ya As Long, xa As Long
    For ya = LBound(arr) To UBound(arr)
        For xa = LBound(brr) To UBound(brr)
            brr(xa) = aSour(ya, xa) = 1
        Next
        arr(ya) = brr
    Next
    
    TransformSourceArray = arr
End Function

Private Sub TextBox5_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean)
    If Not IsDate(TextBox5.Value) Then
        TextBox5.Value = "0:01:00"
        Cancel = True
    End If
End Sub

Private Sub TextBox5_Change()
    ThisWorkbook.Names("остановка_через").RefersToRange.Value = TextBox5.Text
End Sub

Private Sub UserForm_Initialize()
    Randomize
    TextBox5.Text = ThisWorkbook.Names("остановка_через").RefersToRange.Text
    ChangeAddress
End Sub

Private Sub CommandButton1_Click()
    Static dtExit As Date
    On Error Resume Next
    Application.OnTime EarliestTime:=dtExit, Procedure:="SetExitFlag", Schedule:=False
    On Error GoTo 0
    dtExit = Now + CDate(TextBox5.Text)
    exitFlag = False
    Application.OnTime dtExit, "SetExitFlag"
    
    Application.StatusBar = "Следующая остановка после " & Format(dtExit, "hh:mm:ss")
    Me.Hide
    Me.TextBox1.Enabled = False
    Me.TextBox2.Enabled = False
    Me.TextBox3.Enabled = False
    Me.TextBox4.Enabled = False
    
    If dic Is Nothing Then
        Set dic = New Dictionary
        ReDim aComb(1 To UBound(aSour(1)))
'        Лист2.Cells.ClearContents
        Лист2.Select
    End If
    FindBestСombination
    Application.StatusBar = False
End Sub

Private Sub FindBestСombination()
    Do
        VaryComb

        If exitFlag Then
            Exit Do
        End If
        DoEvents
    Loop
    PrintResult aComb
    Me.Show
End Sub
Private Sub VaryComb()
    
    Dim cmpRow As Variant
    Dim optRow As Variant
    Dim optRows As Variant
    Dim cIndx As Variant
    'Dim sDone As String
    Dim aDone As Variant
    ReDim aDone(1 To UBound(aSour)) As Boolean
    
    Dim yf As Long, yo As Long, ySour As Long, nComb As Long
    For yf = 1 To UBound(aSour(1))
        optRows = GetOptRows(cmpRow)
        AddRndRow optRows
        yo = Rnd() * UBound(optRows)
        ySour = optRows(yo)
'        ySour = Int(Rnd() * UBound(aSour)) + 1
        optRow = aSour(ySour)
        cmpRow = SumRows(optRow, cmpRow)
        aDone(ySour) = True
        cIndx = GetIndxArray(aDone)
        nComb = UBound(cIndx)
        GetUniqCountAndAddDic cIndx, nComb
        'Debug.Print yf, ySour, UniqCount(cmpRow), nComb ', sDone
        DoEvents
    Next
End Sub

Private Sub AddRndRow(optRows As Variant)
    ReDim Preserve optRows(LBound(optRows) To UBound(optRows) + 1)
    optRows(UBound(optRows)) = Int(Rnd() * UBound(aSour)) + 1
End Sub

Private Function GetIndxArray(aDone As Variant) As Variant
    Dim va As Variant, ya As Long
    For Each va In aDone
        If va Then ya = ya + 1
    Next
    If ya > 0 Then
        Dim arr As Variant, yDone As Long
        ReDim arr(1 To ya)
        ya = LBound(arr)
        yDone = LBound(aDone)
        For Each va In aDone
            If va Then
                arr(ya) = yDone
                ya = ya + 1
            End If
            yDone = yDone + 1
        Next
        GetIndxArray = arr
    End If
End Function

Private Function GetOptRows(cmpRow As Variant) As Variant
    Dim ya As Long, curCount As Long, optCount As Long, optRows As String, sumRow As Variant
    For ya = 1 To UBound(aSour)
        sumRow = SumRows(aSour(ya), cmpRow)
        curCount = UniqCount(sumRow)
        If optCount < curCount Then
            optCount = curCount
            optRows = ya
        ElseIf curCount = optCount Then
            optRows = optRows & " " & ya
        End If
    Next
    GetOptRows = Split(optRows, " ")
End Function
'    Do
'        aIndx_Init
'        GetUniqCountAndAddDic aIndx
'
'
'        If exitFlag Then
'            Exit Do
'        End If
'        DoEvents
'    Loop
'    PrintResult aComb
'    Me.Show


Private Function SumRows(arr As Variant, brr As Variant) As Variant
    If IsEmpty(brr) Then
        SumRows = arr
        Exit Function
    ElseIf IsEmpty(arr) Then
        SumRows = brr
        Exit Function
    End If
    
    Dim crr As Variant, ya As Long
    ReDim crr(LBound(arr) To UBound(arr)) As Boolean
    For ya = LBound(arr) To UBound(arr)
        crr(ya) = arr(ya) Or brr(ya)
    Next
    SumRows = crr
End Function

Private Function UniqCount(arr As Variant) As Long
    Dim va As Variant
    For Each va In arr
        If va Then UniqCount = UniqCount + 1
    Next
End Function

Private Function GetUniqCountAndAddDic(cIndx As Variant, nComb As Long) As Long
    Dim sIndx As String
    sIndx = Join(cIndx, " ")
    
    If dic.Exists(sIndx) Then
        GetUniqCountAndAddDic = dic(sIndx)
        Exit Function
    End If
    
    Dim curUniqCount As Long
    curUniqCount = CountUniq(cIndx, aSour)
    
    Dim combItem As Variant
    
    If IsEmpty(aComb(nComb)) Then
        ReDim combItem(1 To UBound(aSour(1)))
        aComb(nComb) = combItem
        combItem = Empty
    End If
    
    If IsEmpty(aComb(nComb)(curUniqCount)) Then
        ReDim combItem(1 To 1)
    Else
        combItem = aComb(nComb)(curUniqCount)
        ReDim Preserve combItem(1 To UBound(combItem) + 1)
    End If
    combItem(UBound(combItem)) = cIndx
    aComb(nComb)(curUniqCount) = combItem
    dic(sIndx) = curUniqCount
    GetUniqCountAndAddDic = curUniqCount
End Function

Private Sub aIndx_Init()
    If IsEmpty(aIndx) Then
        ReDim aIndx(1 To 1)
    End If
    
    Dim xa As Long
    For xa = LBound(aIndx) To UBound(aIndx)
        aIndx(xa) = xa
    Next
End Sub

Private Function CountUniq(aIndx As Variant, aSour As Variant) As Long
    Dim iInd As Long, iCount As Long, xs As Long, ys As Long
    Dim aDone As Variant
    ReDim aDone(1 To UBound(aSour(1))) As Boolean
    
    For iInd = LBound(aIndx) To UBound(aIndx)
        ys = aIndx(iInd)
        If ys <= UBound(aSour) Then
            For xs = 1 To UBound(aSour(ys))
                If aSour(ys)(xs) Then
                    If Not aDone(xs) Then
                        aDone(xs) = True
                        iCount = iCount + 1
                    End If
                End If
            Next
        End If
    Next
    CountUniq = iCount
End Function

Private Sub PrintResult(aComb As Variant)
    Dim rTarget As Range
    Set rTarget = Лист2.Cells(1, 1)
    rTarget.Parent.UsedRange.ClearContents
    
    Dim yc As Long, xt As Long
    xt = 1
    For yc = UBound(aComb) To LBound(aComb) Step -1
        If Not IsEmpty(aComb(yc)) Then
            Set rTarget = Лист2.Cells(2, xt)
            rTarget.Cells(0, 1).Resize(1, 2).Value = Array("Комбинаций", yc)
            PrintResultOneCombo aComb(yc), rTarget
            xt = xt + 3
        End If
    Next
    
    rTarget.Parent.Parent.Saved = True
End Sub

Private Sub PrintResultOneCombo(aComb, rTarget As Range)
    rTarget.Cells(1, 1).Resize(1, 3).Value = Array("Уникальных", "Коробки", Empty)
    Set rTarget = rTarget.Cells(2, 1)
    
    Dim yc As Long, yb As Long, arr As Variant, hrr As Variant, brr As Variant
    For yc = UBound(aComb) To LBound(aComb) Step -1
        If Not IsEmpty(aComb(yc)) Then
            arr = aComb(yc)
            ReDim brr(1 To UBound(arr), 1 To 2)
            If rTarget.Row + UBound(brr, 1) > rTarget.Parent.Rows.Count Then
                Set rTarget = rTarget.Cells(1, UBound(brr, 2) + 2).EntireColumn.Cells(1, 1)
                If rTarget.Row + UBound(brr, 1) > rTarget.Parent.Rows.Count Then
                    Exit For
                End If
            End If
            
            For yb = LBound(arr) To UBound(arr)
                brr(yb, 1) = yc
                brr(yb, 2) = Join(arr(yb), ", ")
            Next
            Set rTarget = rTarget.Cells(1, 1).Resize(UBound(brr, 1), UBound(brr, 2))
            rTarget.Value = brr
            Set rTarget = rTarget.Cells(rTarget.Rows.Count + 2, 1)
        End If
    Next
    
End Sub
Задача о рюкзаке в квадрате или нет
 
Вариант с последовательным поиском "лучшей" строки. Если "лучших" строк несколько, то добавляем случайный поиск.
Код
Option Explicit
Private aSour As Variant
Private aIndx As Variant
Private aComb As Variant
Private dic As Dictionary

Private Sub CommandButton2_Click()
    Unload Me
End Sub

Private Sub TextBox1_Change()
    ChangeAddress
End Sub

Private Sub TextBox2_Change()
    ChangeAddress
End Sub

Private Sub TextBox4_Change()
    ChangeAddress
End Sub

Private Sub ChangeAddress()
    Dim rSour As Range
    On Error Resume Next
    Set rSour = Лист1.Range(Me.TextBox4.Value).Resize(TextBox2.Value, TextBox1.Value)
    If Err = 0 Then
        LabelAddress.Caption = rSour.Address(0, 0, xlA1)
        aSour = rSour.Value
        aSour = TransformSourceArray(aSour)
    End If
    On Error GoTo 0
End Sub

Private Function TransformSourceArray(aSour As Variant) As Variant
    Dim arr As Variant, brr As Variant
    ReDim arr(LBound(aSour, 1) To UBound(aSour, 1))
    ReDim brr(LBound(aSour, 2) To UBound(aSour, 2)) As Boolean
    
    Dim ya As Long, xa As Long
    For ya = LBound(arr) To UBound(arr)
        For xa = LBound(brr) To UBound(brr)
            brr(xa) = aSour(ya, xa) = 1
        Next
        arr(ya) = brr
    Next
    
    TransformSourceArray = arr
End Function

Private Sub TextBox5_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean)
    If Not IsDate(TextBox5.Value) Then
        TextBox5.Value = "0:01:00"
        Cancel = True
    End If
End Sub

Private Sub TextBox5_Change()
    ThisWorkbook.Names("остановка_через").RefersToRange.Value = TextBox5.Text
End Sub

Private Sub UserForm_Initialize()
    Randomize
    TextBox5.Text = ThisWorkbook.Names("остановка_через").RefersToRange.Text
    ChangeAddress
End Sub

Private Sub CommandButton1_Click()
    Static dtExit As Date
    On Error Resume Next
    Application.OnTime EarliestTime:=dtExit, Procedure:="SetExitFlag", Schedule:=False
    On Error GoTo 0
    dtExit = Now + CDate(TextBox5.Text)
    exitFlag = False
    Application.OnTime dtExit, "SetExitFlag"
    
    Application.StatusBar = "Следующая остановка после " & Format(dtExit, "hh:mm:ss")
    Me.Hide
    Me.TextBox1.Enabled = False
    Me.TextBox2.Enabled = False
    Me.TextBox3.Enabled = False
    Me.TextBox4.Enabled = False
    
    If dic Is Nothing Then
        Set dic = New Dictionary
        ReDim aComb(1 To UBound(aSour(1)))
'        Лист2.Cells.ClearContents
        Лист2.Select
    End If
    FindBestСombination
End Sub

Private Sub FindBestСombination()
    Do
        VaryComb

        If exitFlag Then
            Exit Do
        End If
        DoEvents
    Loop
    PrintResult aComb
    Me.Show
End Sub
Private Sub VaryComb()
    
    Dim cmpRow As Variant
    Dim optRow As Variant
    Dim optRows As Variant
    Dim cIndx As Variant
    'Dim sDone As String
    Dim aDone As Variant
    ReDim aDone(1 To UBound(aSour)) As Boolean
    
    Dim yf As Long, yo As Long, ySour As Long, nComb As Long
    For yf = 1 To UBound(aSour(1))
        optRows = GetOptRows(cmpRow)
        yo = Rnd() * UBound(optRows)
        ySour = optRows(yo)
        optRow = aSour(ySour)
        cmpRow = SumRows(optRow, cmpRow)
        'sDone = sDone & " " & ySour
        aDone(ySour) = True
        cIndx = GetIndxArray(aDone)
        nComb = UBound(cIndx)
        GetUniqCountAndAddDic cIndx, nComb
        'Debug.Print yf, ySour, UniqCount(cmpRow), nComb ', sDone
        DoEvents
    Next
End Sub

Private Function GetIndxArray(aDone As Variant) As Variant
    Dim va As Variant, ya As Long
    For Each va In aDone
        If va Then ya = ya + 1
    Next
    If ya > 0 Then
        Dim arr As Variant, yDone As Long
        ReDim arr(1 To ya)
        ya = LBound(arr)
        yDone = LBound(aDone)
        For Each va In aDone
            If va Then
                arr(ya) = yDone
                ya = ya + 1
            End If
            yDone = yDone + 1
        Next
        GetIndxArray = arr
    End If
End Function

Private Function GetOptRows(cmpRow As Variant) As Variant
    Dim ya As Long, curCount As Long, optCount As Long, optRows As String, sumRow As Variant
    For ya = 1 To UBound(aSour)
        sumRow = SumRows(aSour(ya), cmpRow)
        curCount = UniqCount(sumRow)
        If optCount < curCount Then
            optCount = curCount
            optRows = ya
        ElseIf curCount = optCount Then
            optRows = optRows & " " & ya
        End If
    Next
    GetOptRows = Split(optRows, " ")
End Function
'    Do
'        aIndx_Init
'        GetUniqCountAndAddDic aIndx
'
'
'        If exitFlag Then
'            Exit Do
'        End If
'        DoEvents
'    Loop
'    PrintResult aComb
'    Me.Show


Private Function SumRows(arr As Variant, brr As Variant) As Variant
    If IsEmpty(brr) Then
        SumRows = arr
        Exit Function
    ElseIf IsEmpty(arr) Then
        SumRows = brr
        Exit Function
    End If
    
    Dim crr As Variant, ya As Long
    ReDim crr(LBound(arr) To UBound(arr)) As Boolean
    For ya = LBound(arr) To UBound(arr)
        crr(ya) = arr(ya) Or brr(ya)
    Next
    SumRows = crr
End Function

Private Function UniqCount(arr As Variant) As Long
    Dim va As Variant
    For Each va In arr
        If va Then UniqCount = UniqCount + 1
    Next
End Function

Private Function GetUniqCountAndAddDic(cIndx As Variant, nComb As Long) As Long
    Dim sIndx As String
    sIndx = Join(cIndx, " ")
    
    If dic.Exists(sIndx) Then
        GetUniqCountAndAddDic = dic(sIndx)
        Exit Function
    End If
    
    Dim curUniqCount As Long
    curUniqCount = CountUniq(cIndx, aSour)
    
    Dim combItem As Variant
    
    If IsEmpty(aComb(nComb)) Then
        ReDim combItem(1 To UBound(aSour(1)))
        aComb(nComb) = combItem
        combItem = Empty
    End If
    
    If IsEmpty(aComb(nComb)(curUniqCount)) Then
        ReDim combItem(1 To 1)
    Else
        combItem = aComb(nComb)(curUniqCount)
        ReDim Preserve combItem(1 To UBound(combItem) + 1)
    End If
    combItem(UBound(combItem)) = cIndx
    aComb(nComb)(curUniqCount) = combItem
    dic(sIndx) = curUniqCount
    GetUniqCountAndAddDic = curUniqCount
End Function

Private Sub aIndx_Init()
    If IsEmpty(aIndx) Then
        ReDim aIndx(1 To 1)
    End If
    
    Dim xa As Long
    For xa = LBound(aIndx) To UBound(aIndx)
        aIndx(xa) = xa
    Next
End Sub

Private Function CountUniq(aIndx As Variant, aSour As Variant) As Long
    Dim iInd As Long, iCount As Long, xs As Long, ys As Long
    Dim aDone As Variant
    ReDim aDone(1 To UBound(aSour(1))) As Boolean
    
    For iInd = LBound(aIndx) To UBound(aIndx)
        ys = aIndx(iInd)
        If ys <= UBound(aSour) Then
            For xs = 1 To UBound(aSour(ys))
                If aSour(ys)(xs) Then
                    If Not aDone(xs) Then
                        aDone(xs) = True
                        iCount = iCount + 1
                    End If
                End If
            Next
        End If
    Next
    CountUniq = iCount
End Function

Private Sub PrintResult(aComb As Variant)
    Dim rTarget As Range
    Set rTarget = Лист2.Cells(1, 1)
    rTarget.Parent.UsedRange.ClearContents
    
    Dim yc As Long, xt As Long
    xt = 1
    For yc = UBound(aComb) To LBound(aComb) Step -1
        If Not IsEmpty(aComb(yc)) Then
            Set rTarget = Лист2.Cells(2, xt)
            rTarget.Cells(0, 1).Resize(1, 2).Value = Array("Комбинаций", yc)
            PrintResultOneCombo aComb(yc), rTarget
            xt = xt + 3
        End If
    Next
    
    rTarget.Parent.Parent.Saved = True
End Sub

Private Sub PrintResultOneCombo(aComb, rTarget As Range)
    rTarget.Cells(1, 1).Resize(1, 3).Value = Array("Уникальных", "Коробки", Empty)
    Set rTarget = rTarget.Cells(2, 1)
    
    Dim yc As Long, yb As Long, arr As Variant, hrr As Variant, brr As Variant
    For yc = UBound(aComb) To LBound(aComb) Step -1
        If Not IsEmpty(aComb(yc)) Then
            arr = aComb(yc)
            ReDim brr(1 To UBound(arr), 1 To 2)
            If rTarget.Row + UBound(brr, 1) > rTarget.Parent.Rows.Count Then
                Set rTarget = rTarget.Cells(1, UBound(brr, 2) + 2).EntireColumn.Cells(1, 1)
                If rTarget.Row + UBound(brr, 1) > rTarget.Parent.Rows.Count Then
                    Exit For
                End If
            End If
            
            For yb = LBound(arr) To UBound(arr)
                brr(yb, 1) = yc
                brr(yb, 2) = Join(arr(yb), ", ")
            Next
            Set rTarget = rTarget.Cells(1, 1).Resize(UBound(brr, 1), UBound(brr, 2))
            rTarget.Value = brr
            Set rTarget = rTarget.Cells(rTarget.Rows.Count + 2, 1)
        End If
    Next
    
End Sub
Изменено: МатросНаЗебре - 19.02.2026 16:52:31
Задача о рюкзаке в квадрате или нет
 
Вариант со случайным поиском. Позволяет искать и среди 1000 строк.
Интерфейс интуитивно понятный. Нажимаете "Продолжить" - поиск продолжится, количество проанализированных вариантов увеличится, вероятность найти большее количество комбинаций возрастает.
Код
Option Explicit
'Private dtExit As Date
Private aSour As Variant
Private aIndx As Variant
Private aComb As Variant
Private dic As Dictionary

Private Sub CommandButton2_Click()
    Unload Me
End Sub

Private Sub TextBox1_Change()
    ChangeAddress
End Sub

Private Sub TextBox2_Change()
    ChangeAddress
End Sub

Private Sub TextBox4_Change()
    ChangeAddress
End Sub

Private Sub ChangeAddress()
    Dim rSour As Range
    On Error Resume Next
    Set rSour = Лист1.Range(Me.TextBox4.Value).Resize(TextBox2.Value, TextBox1.Value)
    If Err = 0 Then
        LabelAddress.Caption = rSour.Address(0, 0, xlA1)
        aSour = rSour.Value
    End If
    On Error GoTo 0
End Sub

Private Sub TextBox5_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean)
    If Not IsDate(TextBox5.Value) Then
        TextBox5.Value = "0:01:00"
        Cancel = True
    End If
End Sub

Private Sub TextBox5_Change()
    ThisWorkbook.Names("остановка_через").RefersToRange.Value = TextBox5.Text
End Sub

Private Sub UserForm_Initialize()
    TextBox5.Text = ThisWorkbook.Names("остановка_через").RefersToRange.Text
    ChangeAddress
End Sub

Private Sub CommandButton1_Click()
    Static dtExit As Date
    On Error Resume Next
    Application.OnTime EarliestTime:=dtExit, Procedure:="SetExitFlag", Schedule:=False
    On Error GoTo 0
    dtExit = Now + CDate(TextBox5.Text)
    exitFlag = False
    Application.OnTime dtExit, "SetExitFlag"
    
    Application.StatusBar = "Следующая остановка после " & Format(dtExit, "hh:mm:ss")
    Me.Hide
    Me.TextBox1.Enabled = False
    Me.TextBox2.Enabled = False
    Me.TextBox3.Enabled = False
    Me.TextBox4.Enabled = False
    
    If dic Is Nothing Then
        Set dic = New Dictionary
        ReDim aComb(1 To UBound(aSour, 2))
        Лист2.Cells.ClearContents
        Лист2.Select
    End If
    FindBestСombination
End Sub

Private Sub FindBestСombination()
    Do
        aIndx_Init
        GetUniqCountAndAddDic aIndx
        
        VaryIndexes
        
        If exitFlag Then
            Exit Do
        End If
        DoEvents
    Loop
    PrintResult aComb
    Me.Show
End Sub

Private Sub VaryIndexes()
    Dim xa As Long
    For xa = LBound(aIndx) To UBound(aIndx)
        'xa = WorksheetFunction.RandBetween(LBound(aIndx), UBound(aIndx))
        VaryIndex xa
    Next
End Sub

Private Sub VaryIndex(xa As Long)
    Dim cIndx As Variant
    cIndx = aIndx
    
    Dim loBo As Long, upBo As Long
    If xa = LBound(aIndx) Then
        loBo = 1
    Else
        loBo = cIndx(xa - 1) + 1
    End If
    If xa = UBound(aIndx) Then
        upBo = UBound(aSour, 1)
    Else
        upBo = cIndx(xa + 1) - 1
        If upBo > UBound(aSour, 1) - UBound(aIndx) + xa Then
            upBo = UBound(aSour, 1) - UBound(aIndx) + xa
        End If
    End If

    Dim yc As Long, optY As Long, curUniqCount As Long, optUniqCount As Long
    For yc = loBo To upBo
        cIndx(xa) = yc
        curUniqCount = GetUniqCountAndAddDic(cIndx)
        If optUniqCount < curUniqCount Then
            optUniqCount = curUniqCount
            optY = yc
        End If
        DoEvents
    Next
    If optY > 0 Then
        aIndx(xa) = optY
    End If
End Sub

Private Function GetUniqCountAndAddDic(cIndx As Variant) As Long
    Dim sIndx As String
    sIndx = Join(cIndx, " ")
    
    If dic.Exists(sIndx) Then
        GetUniqCountAndAddDic = dic(sIndx)
        Exit Function
    End If
    
    Dim curUniqCount As Long
    curUniqCount = CountUniq(cIndx, aSour)
    
    Dim combItem As Variant
    If IsEmpty(aComb(curUniqCount)) Then
        ReDim combItem(1 To 1)
    Else
        combItem = aComb(curUniqCount)
        ReDim Preserve combItem(1 To UBound(combItem) + 1)
    End If
    combItem(UBound(combItem)) = cIndx
    aComb(curUniqCount) = combItem
    dic(sIndx) = curUniqCount
    GetUniqCountAndAddDic = curUniqCount
End Function

Private Sub aIndx_Init()
    If IsEmpty(aIndx) Then
        ReDim aIndx(1 To TextBox3.Value)
    End If
    
    Dim xa As Long, ys As Long, loBo As Long, upBo As Long
    For xa = LBound(aIndx) To UBound(aIndx)
        loBo = ys + 1
        upBo = UBound(aSour, 1) - UBound(aIndx) + xa
        ys = WorksheetFunction.RandBetween(loBo, upBo)
        aIndx(xa) = ys
    Next
End Sub

Private Function CountUniq(aIndx As Variant, aSour As Variant) As Long
    Dim iInd As Long, iCount As Long, xs As Long, ys As Long
    Dim aDone As Variant
    ReDim aDone(1 To UBound(aSour, 2)) As Boolean
    
    For iInd = LBound(aIndx) To UBound(aIndx)
        ys = aIndx(iInd)
        If ys <= UBound(aSour, 1) Then
            For xs = 1 To UBound(aSour, 2)
                If aSour(ys, xs) = 1 Then
                    If Not aDone(xs) Then
                        aDone(xs) = True
                        iCount = iCount + 1
                    End If
                End If
            Next
        End If
    Next
    CountUniq = iCount
End Function

Private Sub PrintResult(aComb)
    Dim rTarget As Range
    Set rTarget = Лист2.Cells(1, 1)
    rTarget.Parent.UsedRange.ClearContents
    rTarget.Cells(1, 1).Resize(1, 3).Value = Array("Уникальных", "Коробки", Empty)
    Set rTarget = rTarget.Cells(2, 1)
    
    Dim yc As Long, yb As Long, arr As Variant, hrr As Variant, brr As Variant
    For yc = UBound(aComb) To LBound(aComb) Step -1
        If Not IsEmpty(aComb(yc)) Then
            arr = aComb(yc)
            ReDim brr(1 To UBound(arr), 1 To 2)
            If rTarget.Row + UBound(brr, 1) > rTarget.Parent.Rows.Count Then
                Set rTarget = rTarget.Cells(1, UBound(brr, 2) + 2).EntireColumn.Cells(1, 1)
                If rTarget.Row + UBound(brr, 1) > rTarget.Parent.Rows.Count Then
                    Exit For
                End If
            End If
            
            For yb = LBound(arr) To UBound(arr)
                brr(yb, 1) = yc
                brr(yb, 2) = Join(arr(yb), ", ")
            Next
            Set rTarget = rTarget.Cells(1, 1).Resize(UBound(brr, 1), UBound(brr, 2))
            rTarget.Value = brr
            Set rTarget = rTarget.Cells(rTarget.Rows.Count + 2, 1)
        End If
    Next
    
    rTarget.Parent.Parent.Saved = True
End Sub
Сумма чисто раб. дней по диапазону дат, с сортировкой по людям и по месяцам.
 
Цитата
написал:
Надо думать что делать с пересекающимися датами...
Как говорится в одном анекдоте:
- Что тут думать, трясти надо!
Подсветил условным форматированием.
Установить максимальные значения осей всех диаграмм на листе равными максимальному значению первой диаграммы
 
Цитата
написал:
и сделайте его невидимым.
Правый клик на оранжевом - Формат ряда данных - ЗАЛИВКА - Нет заливки
Сумма чисто раб. дней по диапазону дат, с сортировкой по людям и по месяцам.
 
Вариант макросом. Кстати,  у Матвея даты в разных строках пересекаются.
Код
Option Explicit
Private Const source_address = "C4:D13"
Private Const target_address = "I4:AF9"

Sub Заполнить_формулы()
    Dim rTarg As Range
    Set rTarg = Range(target_address)
    
    Dim rSour As Range
    Set rSour = Range(source_address)
    
    Dim aSour As Variant
    aSour = rSour.Value
    
    Dim ySour_yTarg As Variant
    ySour_yTarg = GetArrayCorrespondenceYTarget_ySource(rSour.Columns(0), rTarg.Columns(0))
    
    Dim targDates As Variant
    targDates = rTarg.Rows(0).Value
    
    Dim Application_Calculation As XlCalculation: Application_Calculation = Application.Calculation: Application.Calculation = xlCalculationManual
    
    Dim yTarg As Long, xTarg As Long, ySour As Variant, monthEdges As Variant, targDateAddress As String
    For xTarg = 1 To rTarg.Columns.Count
        monthEdges = Array(targDates(1, xTarg), CDate(WorksheetFunction.EoMonth(targDates(1, xTarg), 0)))
        targDateAddress = rTarg.Cells(0, xTarg).Address(0, 0, xlA1)
        For yTarg = 1 To rTarg.Rows.Count
            FillCellFormula rTarg.Cells(yTarg, xTarg), ySour_yTarg(yTarg), monthEdges, aSour, rSour, targDateAddress
        Next
    Next
    
    Application.Calculation = Application_Calculation
End Sub

Private Sub FillCellFormula(clTarg As Range, ySour_yTarg As Variant, monthEdges As Variant, aSour As Variant, rSour As Range, targDateAddress As String)
    If IsEmpty(ySour_yTarg) Then
ClearAndExit:
        clTarg.ClearContents
        clTarg.Interior.Color = RGB(242, 242, 242)
        Exit Sub
    End If
    
    Dim arr As Variant
    
    Dim sFormula As String, ySour As Variant, sBeg As String, sFin As String
    For Each ySour In ySour_yTarg
        If aSour(ySour, 1) <= monthEdges(1) Then
            If aSour(ySour, 2) >= monthEdges(0) Then
                If aSour(ySour, 1) > monthEdges(0) Then
                    sBeg = rSour.Cells(ySour, 1).Address(0, 0, xlA1)
                Else
                    sBeg = targDateAddress
                End If
                If aSour(ySour, 2) < monthEdges(1) Then
                    sFin = rSour.Cells(ySour, 2).Address(0, 0, xlA1)
                Else
                    sFin = "EoMonth(" & targDateAddress & ",0)"
                End If
                
                sFormula = aSour(ySour, 1) & aSour(ySour, 2)
                sFormula = "NETWORKDAYS(" & sBeg & "," & sFin & ",НеРабДни2)"
                AddArr arr, sFormula
            End If
        End If
    Next
    If IsEmpty(arr) Then GoTo ClearAndExit
    sFormula = "= " & Join(arr, "+")
    clTarg.Formula = sFormula
    
    If UBound(arr) > 1 Then
        clTarg.Interior.Color = RGB(255, 255, 100)
    End If
End Sub

Private Sub AddArr(arr As Variant, sFormula As String)
    If IsEmpty(arr) Then
        ReDim arr(1 To 1)
    Else
        ReDim Preserve arr(LBound(arr) To UBound(arr) + 1)
    End If
    arr(UBound(arr)) = sFormula
End Sub

Private Function GetArrayCorrespondenceYTarget_ySource(rSour As Range, rTarg As Range)
    Dim dicNamesY As Object
    Set dicNamesY = GetNamesYdic(rSour)
    
    Dim aTarg As Variant
    aTarg = rTarg.Value
    Dim res As Variant
    ReDim res(1 To UBound(aTarg, 1))
    
    Dim yt As Long
    For yt = 1 To UBound(res)
        If dicNamesY.Exists(aTarg(yt, 1)) Then
            res(yt) = dicNamesY(aTarg(yt, 1)).Keys()
        End If
    Next
    GetArrayCorrespondenceYTarget_ySource = res
End Function

Private Function GetNamesYdic(rSour As Range) As Object
    Dim dic As Object
    Set dic = CreateObject("Scripting.Dictionary")
    
    Dim arr As Variant
    arr = rSour.Value
    
    Dim ya As Long, sName As String
    For ya = 1 To UBound(arr, 1)
        sName = arr(ya, 1)
        If Not dic.Exists(sName) Then
            Set dic(sName) = CreateObject("Scripting.Dictionary")
        End If
        dic(sName)(ya) = Empty
    Next
    
    Set GetNamesYdic = dic
End Function
Установить максимальные значения осей всех диаграмм на листе равными максимальному значению первой диаграммы
 
Правый клик на диаграмме-Выбрать данные-Добавить
Копирование данных с одного листа на другой
 
Как вы замахнулись сразу на ленту :D
Код
sub macro_01(control IRibbonControl)
    tt
End sub
Установить максимальные значения осей всех диаграмм на листе равными максимальному значению первой диаграммы
 
Хорошая идея. Добавьте ряд в каждую диаграмму с максимальным значением по всем месяцам, и сделайте его невидимым.
[ Закрыто] Проверить макрос, исправит расчеты
 
Выглядит как ТЗ  :D
Если перенесут в платную ветку, я претендую.
Установить максимальные значения осей всех диаграмм на листе равными максимальному значению первой диаграммы
 
Код
Sub FixAxes()
    Dim ch As ChartObject, maxScale As Variant, minScale As Double
    For Each ch In ActiveSheet.ChartObjects
        If IsEmpty(maxScale) Then
            maxScale = ch.Chart.Axes(xlValue).MaximumScale
            minScale = ch.Chart.Axes(xlValue).MinimumScale
        Else
            ch.Chart.Axes(xlValue).MaximumScale = maxScale
            ch.Chart.Axes(xlValue).MinimumScale = minScale
        End If
    Next
End Sub
Вариант названия темы:
Установить максимальные значения осей всех диаграмм на листе равными максимальному значению первой диаграммы.
Копирование данных с одного листа на другой
 
Цитата
написал:
Сейчас это стало кнопкой риббона, там всего 3 кнопки, остальное заблокировано, оно ещё и от названия влияет
Ничего непонятно, но очень интересно.
Код
Option Explicit
Private Const CONTROL_LINE = "H13:AL27 H61:AL75"

Sub tt()
    If TypeName(Selection) <> "Range" Then ActiveCell.Select

    Dim vAddress As Variant, col As New Collection, addAllFlag As Boolean
for_begin:
    For Each vAddress In Split(CONTROL_LINE)
        If Not Intersect(Selection, Range(vAddress)) Is Nothing Or addAllFlag Then
            col.Add vAddress
        End If
    Next
    If col.Count = 0 Then
        addAllFlag = True
        GoTo for_begin
    End If
    
    For Each vAddress In col
        Debug.Print Now, vAddress
        tt_adr vAddress
    Next
End Sub

Private Sub tt_adr(ByVal sourceAddress As String)
    Dim rSource As Range
    Set rSource = Sheets("ОДНОСТРОЧНЫЙ").Range(sourceAddress)
    With rSource
        Dim ad_ As String
        ad_ = .Address
        Dim nr_ As Long
        nr_ = .Rows.Count
    End With
      
    Dim rTarget As Range
    Set rTarget = Sheets("СУДОВОЙ").Range(ad_).Cells(1, 1)
      
    Application.ScreenUpdating = False
    Dim Application_Calculation As XlCalculation: Application_Calculation = Application.Calculation: Application.Calculation = xlCalculationManual
      
    Dim ys As Long, xs As Long, yt As Long, xw As Long, vv As Variant
    For ys = 1 To rSource.Rows.Count
        CopyRange 1, 15, True, ys, rSource, yt, rTarget
        CopyRange 16, 16, False, ys, rSource, yt, rTarget
    Next
    Calculate
    Application.Calculation = Application_Calculation
    Application.ScreenUpdating = True
End Sub
 
Private Sub CopyRange(xs As Long, xw As Long, needClear As Boolean, ys As Long, rSource As Range, yt As Long, rTarget As Range)
    yt = yt + 1
    If needClear Then
        rTarget(yt, xw + 1).Clear
        With rTarget(yt, xw + 1).Borders
            .LineStyle = xlContinuous
            .ColorIndex = 0
            .TintAndShade = 0
            .Weight = xlThin
        End With
    End If
    rSource.Cells(ys, xs).Resize(1, xw).copy
    rTarget(yt, 1).PasteSpecial Paste:=xlPasteValues
    rTarget(yt, 1).PasteSpecial Paste:=xlPasteFormats
End Sub
Копирование данных с одного листа на другой
 
Цитата
написал:
Это получается 3 кода
Чё это вдруг?  :D  Везде название процедуры одно и то же. Если вызывали tt, то и вызывайте tt.
Сумма чисто раб. дней по диапазону дат, с сортировкой по людям и по месяцам.
 
Ещё вариант формулы массива.
Код
=СУММ(($C$4:$C$13<=КОНМЕСЯЦА(I$3;0))*($D$4:$D$13>=I$3)*ЧИСТРАБДНИ(ЕСЛИ($C$4:$C$13>I$3;$C$4:$C$13;I$3);ЕСЛИ($D$4:$D$13<КОНМЕСЯЦА(I$3;0);$D$4:$D$13;КОНМЕСЯЦА(I$3;0));НеРабДни2)*($B$4:$B$13=$H4))
Изменено: МатросНаЗебре - 18.02.2026 12:33:03
Копирование данных с одного листа на другой
 
Код
Sub tt()
    tt_adr "H13:AL27"
    tt_adr "H61:AL75"
End Sub

Sub tt_adr(sourceAddress As String)
    Dim rSource As Range
    Set rSource = Sheets("ОДНОСТРОЧНЫЙ").Range(sourceAddress)
    With rSource
        Dim ad_ As String
        ad_ = .Address
        Dim nr_ As Long
        nr_ = .Rows.Count
    End With
      
    Dim rTarget As Range
    Set rTarget = Sheets("СУДОВОЙ").Range(ad_).Cells(1, 1)
      
    Application.ScreenUpdating = False
    Dim Application_Calculation As XlCalculation: Application_Calculation = Application.Calculation: Application.Calculation = xlCalculationManual
      
    Dim ys As Long, xs As Long, yt As Long, xw As Long, vv As Variant
    For ys = 1 To rSource.Rows.Count
        CopyRange 1, 15, True, ys, rSource, yt, rTarget
        CopyRange 16, 16, False, ys, rSource, yt, rTarget
    Next
    Calculate
    Application.Calculation = Application_Calculation
    Application.ScreenUpdating = True
End Sub
 
Private Sub CopyRange(xs As Long, xw As Long, needClear As Boolean, ys As Long, rSource As Range, yt As Long, rTarget As Range)
    yt = yt + 1
    If needClear Then
        rTarget(yt, xw + 1).Clear
        With rTarget(yt, xw + 1).Borders
            .LineStyle = xlContinuous
            .ColorIndex = 0
            .TintAndShade = 0
            .Weight = xlThin
        End With
    End If
    rSource.Cells(ys, xs).Resize(1, xw).copy
    rTarget(yt, 1).PasteSpecial Paste:=xlPasteValues
    rTarget(yt, 1).PasteSpecial Paste:=xlPasteFormats
End Sub
Расчет годового дохода по депозиту., Расчет годового дохода по депозиту с ежемесячным пополнением, без возможностия снятия и ежемесячно меняющейся ставкой доходности
 
Цитата
написал:
мне нужна именно степенная аппроксимация. Т.е. доход второго месяца = дохода от первого месяца на вложения в начале первого месяца + доход от вложений первого и второго месяца по ставке, действующей с начала второго месяца.
Не факт. Из того, что Вам нужно посчитать доход второго месяца по описанной формуле, не следует, что Вам нужна именно степенная аппроксимация. Для этой формулы подойдёт и степенная, и линейная аппроксимация. Результат будет разный, но формула будет работать. Эта формула не определяет тип аппроксимации. Тип аппроксимации определяется тем, как Вы переводите годовой процент в месячный.
Цитата
написал:
Не совсем вас понял. У меня не стоит задача рассчитать %, он устанавливается банком и может периодически меняться.
А ещё банком устанавливается порядок пересчёта процента из годового в месячный. Если используется линейная аппроксимация - возьмите левый блок, если степенная - возьмите правый блок.
Задача о рюкзаке в квадрате или нет
 
Изменён алгоритм перебора. Этот вариант работает несколько быстрее.
Код
Option Explicit
'v3
Public Const N_BOX = 3
Public Const N_PREDMET = 74
Public Const K_BOX = 50 '1000

Sub test3()
    CloseEmptyWb
    FindBestСombination nBox:=N_BOX, rSource:=Лист1.Range("B2").Resize(K_BOX, N_PREDMET)
End Sub

Private Sub FindBestСombination(nBox As Long, rSource As Range)
    Dim aSour As Variant
    aSour = rSource.Value
    
    Dim aIndx As Variant, flagExit As Boolean
    ReDim aIndx(1 To nBox)
    Init_aIndx aIndx
    
    Dim aComb As Variant, combItem As Variant
    ReDim aComb(1 To UBound(aSour, 2))
    
    Dim dt As Date, dtStart As Date
    dtStart = Now
    
    Dim curUniqCount As Long
    Do
'        Debug.Print Join(aIndx, " ")
'        If Not HasDupies(aIndx) Then
'            If IsIncreasing(aIndx) Then
                curUniqCount = CountUniq(aIndx, aSour)
                If IsEmpty(aComb(curUniqCount)) Then
                    ReDim combItem(1 To 1)
                Else
                    combItem = aComb(curUniqCount)
                    ReDim Preserve combItem(1 To UBound(combItem) + 1)
                End If
                combItem(UBound(combItem)) = aIndx
                aComb(curUniqCount) = combItem
'            End If
'        End If
        If dt < Now - TimeSerial(0, 0, 5) Then
            dt = Now
            Application.StatusBar = Left("Перебираю " & Join(aIndx, " "), 125)
        End If
        
        PlusOne aIndx, 1, flagExit, UBound(aSour, 1)
        If flagExit Then Exit Do
        DoEvents
    Loop
    Debug.Print "test3", Format(Now - dtStart, "hh:mm:ss")
    
    PrintResult aComb, rSource
    
    Application.StatusBar = False
End Sub

Private Sub PrintResult(aComb, rSource As Range)
    Dim rTarget As Range
    Set rTarget = Workbooks.Add(1).Sheets(1).Cells(1, 1)
    rTarget.Cells(1, 1).Resize(1, 3).Value = Array("Уникальных", "Коробки", Empty)
    Set rTarget = rTarget.Cells(2, 1)
    
    Dim aSource As Variant
    aSource = rSource.Columns(0).Value
    
    Dim yc As Long, yb As Long, arr As Variant, hrr As Variant, brr As Variant
    For yc = UBound(aComb) To LBound(aComb) Step -1
        If Not IsEmpty(aComb(yc)) Then
            Application.StatusBar = "Вывожу " & yc
            arr = aComb(yc)
            ReDim brr(1 To UBound(arr), 1 To 3)
            If rTarget.Row + UBound(brr, 1) > rTarget.Parent.Rows.Count Then
                Set rTarget = rTarget.Cells(1, UBound(brr, 2) + 2).EntireColumn.Cells(1, 1)
                If rTarget.Row + UBound(brr, 1) > rTarget.Parent.Rows.Count Then
                    Exit For
                End If
            End If
            
            For yb = LBound(arr) To UBound(arr)
                hrr = GetHeader(arr(yb), aSource)
                brr(yb, 1) = yc
                brr(yb, 2) = Join(arr(yb), ", ")
                brr(yb, 3) = Join(hrr, ", ")
            Next
            Set rTarget = rTarget.Cells(1, 1).Resize(UBound(brr, 1), UBound(brr, 2))
            rTarget.Value = brr
            Application.Goto rTarget
            Set rTarget = rTarget.Cells(rTarget.Rows.Count + 2, 1)
        End If
    Next
    
    Application.Goto Cells(1, 1)
    rTarget.Parent.Parent.Saved = True
End Sub

Private Function GetHeader(arr As Variant, aSource As Variant) As Variant
    Dim hrr As Variant, yh As Long
    ReDim hrr(LBound(arr) To UBound(arr))
    yh = LBound(hrr) - 1
    
    Dim ya As Variant
    For Each ya In arr
        yh = yh + 1
        If ya <= UBound(aSource, 1) Then
            hrr(yh) = aSource(ya, 1)
        End If
    Next
    GetHeader = hrr
End Function

Private Sub PlusOne(aIndx As Variant, level As Long, flagExit As Boolean, maxIndex As Long)
    If flagExit Then Exit Sub
    Dim xi As Long
    If aIndx(level) < maxIndex - level + 1 Then
        aIndx(level) = aIndx(level) + 1
    
        For xi = level - 1 To LBound(aIndx) Step -1
            If aIndx(xi + 1) < maxIndex Then
                If aIndx(xi) < aIndx(xi + 1) + 1 Then
                    aIndx(xi) = aIndx(xi + 1) + 1
                End If
            Else
                Exit For
            End If
        Next
    Else
        If level < UBound(aIndx) Then
            PlusOne aIndx, level + 1, flagExit, maxIndex

            For xi = level To LBound(aIndx) Step -1
                If aIndx(xi + 1) < maxIndex Then
                    aIndx(xi) = aIndx(xi + 1) + 1
                Else
'                    If level + 2 <= UBound(aIndx) Then
'                        PlusOne aIndx, level + 2, flagExit, maxIndex
'                    End If
                    Exit For
                End If
            Next
        Else
            flagExit = True
        End If
    End If
End Sub

Private Function CountUniq(aIndx As Variant, aSour As Variant) As Long
    Dim iInd As Long, iCount As Long, xs As Long, ys As Long
    Dim aDone As Variant
    ReDim aDone(1 To UBound(aSour, 2)) As Boolean
    
    For iInd = LBound(aIndx) To UBound(aIndx)
        ys = aIndx(iInd)
        If ys <= UBound(aSour, 1) Then
            For xs = 1 To UBound(aSour, 2)
                If aSour(ys, xs) = 1 Then
                    If Not aDone(xs) Then
                        aDone(xs) = True
                        iCount = iCount + 1
                    End If
                End If
            Next
        End If
    Next
    CountUniq = iCount
End Function

Private Sub Init_aIndx(aIndx As Variant)
    Dim iInd As Long
    For iInd = LBound(aIndx) To UBound(aIndx)
        aIndx(iInd) = UBound(aIndx) - iInd + 1
    Next
End Sub

Private Sub CloseEmptyWb()
    Dim wb As Workbook
    For Each wb In Application.Workbooks
        If wb.Path = "" Then wb.Close False
    Next
End Sub
Задача о рюкзаке в квадрате или нет
 
Цитата
написал:
Коробка №1, Коробка №5, Коробка №6 с 29-ью уникальными предметами.
Поправил.
Скрытый текст
Расчет годового дохода по депозиту., Расчет годового дохода по депозиту с ежемесячным пополнением, без возможностия снятия и ежемесячно меняющейся ставкой доходности
 
Цитата
написал:
почему у банка сходится как раз с линейным расчётом? )
Не значит, что это правильно  :D
Как я уже писал,
Цитата
написал:
это неправильно, но почему-то многие так делают
Если каждый месяц будет "годовой процент/12" то через 12 месяцев не будет "годовой процент".
В приложенном файле привёл пример, если положить 1000 руб на 12 месяцев под 12% годовых.
Линейный расчёт не приводит к 12%.
Задача о рюкзаке в квадрате или нет
 
Вариант макросом. Менять параметры можно с помощью констант, расположенных в верхней части.
Данный код настроен для перебора 3 коробок из 50, для 74 предметов.
Подобные задачи достаточно ресурсоёмкие, перебор всех комбинаций потребует некоторого терпения  :D
Код
Option Explicit
Private Const N_BOX = 3
Private Const N_PREDMET = 74
Private Const K_BOX = 50 '1000

Sub test()
    CloseEmptyWb
    FindBestСombination nBox:=N_BOX, rSource:=Лист1.Range("B2").Resize(K_BOX, N_PREDMET)
End Sub

Private Sub FindBestСombination(nBox As Long, rSource As Range)
    Dim aSour As Variant
    aSour = rSource.Value
    
    Dim aIndx As Variant, flagExit As Boolean
    ReDim aIndx(1 To nBox)
    Init_aIndx aIndx
    
    Dim aComb As Variant, combItem As Variant
    ReDim aComb(1 To UBound(aSour, 2))
    
    Dim dt As Date
    Dim curUniqCount As Long
    Do
        If Not HasDupies(aIndx) Then
            If IsIncreasing(aIndx) Then
                curUniqCount = CountUniq(aIndx, aSour)
                If IsEmpty(aComb(curUniqCount)) Then
                    ReDim combItem(1 To 1)
                Else
                    ReDim Preserve combItem(1 To UBound(combItem) + 1)
                End If
                combItem(UBound(combItem)) = aIndx
                aComb(curUniqCount) = combItem
            End If
        End If
        If dt < Now - TimeSerial(0, 0, 5) Then
            dt = Now
            Application.StatusBar = Left("Перебираю " & Join(aIndx, " "), 125)
        End If
        
        PlusOne aIndx, 1, flagExit, UBound(aSour, 1)
        If flagExit Then Exit Do
        DoEvents
    Loop
    PrintResult aComb, rSource
    
    Application.StatusBar = False
End Sub

Private Sub PrintResult(aComb, rSource As Range)
    Dim rTarget As Range
    Set rTarget = Workbooks.Add(1).Sheets(1).Cells(1, 1)
    rTarget.Cells(1, 1).Resize(1, 3).Value = Array("Уникальных", "Коробки", Empty)
    Set rTarget = rTarget.Cells(2, 1)
    
    Dim aSource As Variant
    aSource = rSource.Columns(0).Value
    
    Dim yc As Long, yb As Long, arr As Variant, hrr As Variant, brr As Variant
    For yc = UBound(aComb) To LBound(aComb) Step -1
        If Not IsEmpty(aComb(yc)) Then
            Application.StatusBar = "Вывожу " & yc
            arr = aComb(yc)
            ReDim brr(1 To UBound(arr), 1 To 3)
            If rTarget.Row + UBound(brr, 1) > rTarget.Parent.Rows.Count Then Exit For
            
            For yb = LBound(arr) To UBound(arr)
                hrr = GetHeader(arr(yb), aSource)
                brr(yb, 1) = yc
                brr(yb, 2) = Join(arr(yb), ", ")
                brr(yb, 3) = Join(hrr, ", ")
            Next
            Set rTarget = rTarget.Cells(1, 1).Resize(UBound(brr, 1), UBound(brr, 2))
            rTarget.Value = brr
            Application.Goto rTarget
            Set rTarget = rTarget.Cells(rTarget.Rows.Count + 1, 1)
        End If
    Next
    
    Application.Goto Cells(1, 1)
    rTarget.Parent.Parent.Saved = True
End Sub

Private Function GetHeader(arr As Variant, aSource As Variant) As Variant
    Dim hrr As Variant, yh As Long
    ReDim hrr(LBound(arr) To UBound(arr))
    yh = LBound(hrr) - 1
    
    Dim ya As Variant
    For Each ya In arr
        yh = yh + 1
        hrr(yh) = aSource(ya, 1)
    Next
    GetHeader = hrr
End Function

Private Function IsIncreasing(aIndx As Variant) As Boolean
    Dim xi As Long, hi As Long
    For xi = LBound(aIndx) To UBound(aIndx) - 1
        For hi = xi + 1 To UBound(aIndx)
            If aIndx(xi) >= aIndx(hi) Then
                IsIncreasing = False
                Exit Function
            End If
        Next
    Next
    IsIncreasing = True
End Function

Private Function HasDupies(aIndx As Variant) As Boolean
    Dim xi As Long, hi As Long
    For xi = LBound(aIndx) To UBound(aIndx) - 1
        For hi = xi + 1 To UBound(aIndx)
            If aIndx(xi) = aIndx(hi) Then
                HasDupies = True
                Exit Function
            End If
        Next
    Next
End Function

Private Sub PlusOne(aIndx As Variant, level As Long, flagExit As Boolean, maxIndex As Long)
    If flagExit Then Exit Sub
    If aIndx(level) < maxIndex Then
        aIndx(level) = aIndx(level) + 1
'        ShiftRight aIndx, level, flagExit, maxIndex, False
    Else
        If level < UBound(aIndx) Then
            Dim xi As Long
            For xi = LBound(aIndx) To level
                aIndx(xi) = 1 'xi
            Next
            
'            Dim flagPlus As Boolean
'            ShiftRight aIndx, level, flagExit, maxIndex, flagPlus
'
'            If flagPlus Or True Then
                PlusOne aIndx, level + 1, flagExit, maxIndex
'            End If
        Else
            flagExit = True
        End If
    End If
End Sub

'Private Sub ShiftRight(aIndx As Variant, level As Long, flagExit As Boolean, maxIndex As Long, flagPlus As Boolean)
'    Exit Sub
'    Dim xi As Long
'    For xi = level + 1 To UBound(aIndx)
'        If aIndx(xi) <= aIndx(xi - 1) Then
'            If aIndx(xi) < maxIndex Then
'                aIndx(xi) = aIndx(xi - 1) + 1
'                If xi = level + 1 Then
'                    flagPlus = True
'                End If
'            Else
'                flagExit = True
'                Exit Sub
'            End If
'        End If
'    Next
'
'End Sub

Private Function CountUniq(aIndx As Variant, aSour As Variant) As Long
    Dim iInd As Long, iCount As Long, xs As Long, ys As Long
    Dim aDone As Variant
    ReDim aDone(1 To UBound(aSour, 2)) As Boolean
    
    For iInd = LBound(aIndx) To UBound(aIndx)
        ys = aIndx(iInd)
        For xs = 1 To UBound(aSour, 2)
            If aSour(ys, xs) = 1 Then
                If Not aDone(xs) Then
                    aDone(xs) = True
                    iCount = iCount + 1
                End If
            End If
        Next
    Next
    CountUniq = iCount
End Function

Private Sub Init_aIndx(aIndx As Variant)
    Dim iInd As Long
    For iInd = LBound(aIndx) To UBound(aIndx)
        aIndx(iInd) = 1 'iInd
    Next
End Sub

Private Sub CloseEmptyWb()
    Dim wb As Workbook
    For Each wb In Application.Workbooks
        If wb.Path = "" Then wb.Close False
    Next
End Sub
Расчет годового дохода по депозиту., Расчет годового дохода по депозиту с ежемесячным пополнением, без возможностия снятия и ежемесячно меняющейся ставкой доходности
 
У вас процент в месяц считается как 1/12 от годового процента.
Вообще-то это неправильно, но почему-то многие так делают, в приложенном файле я сделал два варианта: линейный и степенной.
Извлечь дополнительные данные из функции пользователя
 
Вариант 1 и 3 потребует переделки в других местах, где упоминается функция.
Вариант 2 и 4 - не потребует.
Обнулять переменные - хорошая практика.
Изменено: МатросНаЗебре - 16.02.2026 13:08:41
Формула, выводящая текст, только если в соседней ячейке внесены значения, формула не работает как хотелось бы
 
Код
=ЕСЛИ(G2="";"";ЕСЛИ(СЧЁТЕСЛИ($F$2:$F$137;H2)<>0;"маркировка есть";"маркировки нет"))
Вариант названия темы
Формула, выводящая текст, только если в соседней ячейке внесены значения.
Извлечь дополнительные данные из функции пользователя
 
Вариант 4. Рефакторинг исходной функции.
Код
Private Sub CommandButton1_Click()
    x = Range("A1:J" & Cells(Rows.Count, 1).End(xlUp).Row).Value
    
    For i = 1 To UBound(x) 'расчет номера 1 строки реестра
        If x(i, 1) = "ГНН-0001" And CDate(x(i, 3)) = #1/1/2023# Then Exit For
    Next i
                    
    With Cells(i, 1).Resize(UBound(ArrAutofilterNew(x, "1=" & "ГНН-0001", "3=" & #1/1/2023#)), 10).Interior
    'раскраска ячеек
    End With
    
    Debug.Print ArrAutofilterNew_GetRfirst(x, "1=" & "ГНН-0001", "3=" & #1/1/2023#)
End Sub

Function ArrAutofilterNew_GetRfirst(ByRef arr, ParamArray args() As Variant) As Variant   ' Новая версия функции ArrAutofilter, от января 2021 года.  © ExcelVBA.ru

    Dim RowsCount&, i As Long, j As Long, arrCheck As Variant

    arrCheck = GetArrCheck(arr, RowsCount, args)

    For i = LBound(arr, 1) To UBound(arr, 1)    ' снова перебираем все строки массива
        If arrCheck(i) Then ' если строка ранее помечена как подходящая
            ArrAutofilterNew_GetRfirst = i
            Exit Function
        End If
    Next i
End Function

Function ArrAutofilterNew(ByRef arr, ParamArray args() As Variant) As Variant   ' Новая версия функции ArrAutofilter, от января 2021 года.  © ExcelVBA.ru

    Dim RowsCount&, i As Long, j As Long, arrCheck As Variant, ro&

    arrCheck = GetArrCheck(arr, RowsCount, args)

    ReDim newarr(1 To RowsCount&, LBound(arr, 2) To UBound(arr, 2)) ' формируем новый массив
    For i = LBound(arr, 1) To UBound(arr, 1)    ' снова перебираем все строки массива
        If arrCheck(i) Then ' если строка ранее помечена как подходящая
            ro& = ro& + 1 ' вычисляем номер строки в новом массиве
            For j = LBound(arr, 2) To UBound(arr, 2)
                newarr(ro&, j) = arr(i, j) ' заполняем массив значениями из исходного
            Next j
        End If
    Next i
    ArrAutofilterNew = newarr ' возвращаем результат
End Function

Function GetArrCheck(ByRef arr, RowsCount&, ParamArray args() As Variant) As Variant
    On Error Resume Next
    GetArrCheck = False ' возвращаемое значение в случае ошибки
    If UBound(args) = -1 Then Debug.Print "Array filtering error: filters required": Exit Function
    ReDim Filters(1 To UBound(args(0)) + 1, 1 To 2)

    Dim i&, ColumnToCheck&, FiltersCount&, j&:  Err.Clear: i& = UBound(arr, 2)
    If Err.Number > 0 Then Debug.Print "Array filtering error: two dimensional array required": Exit Function

    For i& = LBound(args(0)) To UBound(args(0))    ' перебираем все параметры фильтрации
        If Not IsMissing(args(0)(i&)) Then
            If args(0)(i&) Like "#*=*" Then ' распознаем параметры фильтрации
                FiltersCount& = FiltersCount& + 1
                Filters(FiltersCount&, 1) = Val(Split(args(0)(i&), "=")(0)) ' столбец массива
                Filters(FiltersCount&, 2) = Split(args(0)(i&), "=", 2)(1) ' маска для значения
            Else ' неверно заданный фильтр
                Debug.Print "ArrAutofilterNew error: invalid filter «" & args(0)(i&) & "»"
            End If
        End If
    Next i&
    If FiltersCount& = 0 Then Debug.Print "Array filtering error: all filters are empty": Exit Function

    ReDim arrCheck(LBound(arr, 1) To UBound(arr, 1)) As Boolean ' для результатов проверки
    For i = LBound(arr, 1) To UBound(arr, 1)    ' перебираем все строки массива, и проверяем их
        arrCheck(i) = True
        For j& = 1 To FiltersCount&    ' перебираем все параметры фильтрации
            If Not (arr(i, Filters(j&, 1)) Like Filters(j&, 2)) Then arrCheck(i) = False: Exit For
        Next j&
        RowsCount& = RowsCount& - arrCheck(i) ' увеличиваем счётчик подходящих строк на 1
    Next i
    If RowsCount& = 0 Then Exit Function ' выход, если нет ни одной подходящей строки в массиве
    GetArrCheck = arrCheck
End Function
Извлечь дополнительные данные из функции пользователя
 
Вариант 3. Вернуть массив из двух элементов.
Код
Private Sub CommandButton1_Click()
    x = Range("A1:J" & Cells(Rows.Count, 1).End(xlUp).Row).Value
    
    For i = 1 To UBound(x) 'расчет номера 1 строки реестра
        If x(i, 1) = "ГНН-0001" And CDate(x(i, 3)) = #1/1/2023# Then Exit For
    Next i
                    
    Dim arr As Variant
    arr = ArrAutofilterNew(x, "1=" & "ГНН-0001", "3=" & #1/1/2023#)
                    
    With Cells(i, 1).Resize(UBound(arr(0)), 10).Interior
    'раскраска ячеек
    End With
    Debug.Print arr(1)
    
End Sub

'---------------------------------------------
Function ArrAutofilterNew(ByRef arr, ParamArray args() As Variant) As Variant   ' Новая версия функции ArrAutofilter, от января 2021 года.  © ExcelVBA.ru
    ' Получает по ссылке массив ARR для фильтрации
    ' и список критериев фильтрации в формате "3=маска текста" (номер столбца, "=", искомое значение)
    ' Возвращает двумерный массив с подходящими строками
     
    On Error Resume Next
    ArrAutofilterNew = False ' возвращаемое значение в случае ошибки
    If UBound(args) = -1 Then Debug.Print "Array filtering error: filters required": Exit Function
    ReDim Filters(1 To UBound(args) + 1, 1 To 2)
  
    Dim i&, ColumnToCheck&, FiltersCount&, j&, ro&, RowsCount&:  Err.Clear: i& = UBound(arr, 2)
    If Err.Number > 0 Then Debug.Print "Array filtering error: two dimensional array required": Exit Function
  
    For i& = LBound(args) To UBound(args)    ' перебираем все параметры фильтрации
        If Not IsMissing(args(i&)) Then
            If args(i&) Like "#*=*" Then ' распознаем параметры фильтрации
                FiltersCount& = FiltersCount& + 1
                Filters(FiltersCount&, 1) = Val(Split(args(i&), "=")(0)) ' столбец массива
                Filters(FiltersCount&, 2) = Split(args(i&), "=", 2)(1) ' маска для значения
            Else ' неверно заданный фильтр
                Debug.Print "ArrAutofilterNew error: invalid filter «" & args(i&) & "»"
            End If
        End If
    Next i&
    If FiltersCount& = 0 Then Debug.Print "Array filtering error: all filters are empty": Exit Function
  
    ReDim arrCheck(LBound(arr, 1) To UBound(arr, 1)) As Boolean ' для результатов проверки
    For i = LBound(arr, 1) To UBound(arr, 1)    ' перебираем все строки массива, и проверяем их
        arrCheck(i) = True
        For j& = 1 To FiltersCount&    ' перебираем все параметры фильтрации
            If Not (arr(i, Filters(j&, 1)) Like Filters(j&, 2)) Then arrCheck(i) = False: Exit For
        Next j&
        RowsCount& = RowsCount& - arrCheck(i) ' увеличиваем счётчик подходящих строк на 1
    Next i
    If RowsCount& = 0 Then Exit Function ' выход, если нет ни одной подходящей строки в массиве
     
    Dim rFirst As Long
     
    ReDim newarr(1 To RowsCount&, LBound(arr, 2) To UBound(arr, 2)) ' формируем новый массив
    For i = LBound(arr, 1) To UBound(arr, 1)    ' снова перебираем все строки массива
        If arrCheck(i) Then ' если строка ранее помечена как подходящая
            ro& = ro& + 1 ' вычисляем номер строки в новом массиве
            If rFirst = 0 Then rFirst = i
            For j = LBound(arr, 2) To UBound(arr, 2)
                newarr(ro&, j) = arr(i, j) ' заполняем массив значениями из исходного
            Next j
        End If
    Next i
    ArrAutofilterNew = Array(newarr, rFirst) ' возвращаем результат
    Erase arrCheck
End Function
Извлечь дополнительные данные из функции пользователя
 
Вариант 2. Передать через глобальную переменную.
Код
Private Sub CommandButton1_Click()
    x = Range("A1:J" & Cells(Rows.Count, 1).End(xlUp).Row).Value
    
    For i = 1 To UBound(x) 'расчет номера 1 строки реестра
        If x(i, 1) = "ГНН-0001" And CDate(x(i, 3)) = #1/1/2023# Then Exit For
    Next i
                    
    With Cells(i, 1).Resize(UBound(ArrAutofilterNew(x, "1=" & "ГНН-0001", "3=" & #1/1/2023#)), 10).Interior
    'раскраска ячеек
    End With
    Debug.Print rFirst
    
End Sub

'---------------------------------------------
Public rFirst As Long
Function ArrAutofilterNew(ByRef arr, ParamArray args() As Variant) As Variant   ' Новая версия функции ArrAutofilter, от января 2021 года.  © ExcelVBA.ru
    ' Получает по ссылке массив ARR для фильтрации
    ' и список критериев фильтрации в формате "3=маска текста" (номер столбца, "=", искомое значение)
    ' Возвращает двумерный массив с подходящими строками
     
    On Error Resume Next
    ArrAutofilterNew = False ' возвращаемое значение в случае ошибки
    If UBound(args) = -1 Then Debug.Print "Array filtering error: filters required": Exit Function
    ReDim Filters(1 To UBound(args) + 1, 1 To 2)
  
    Dim i&, ColumnToCheck&, FiltersCount&, j&, ro&, RowsCount&:  Err.Clear: i& = UBound(arr, 2)
    If Err.Number > 0 Then Debug.Print "Array filtering error: two dimensional array required": Exit Function
  
    For i& = LBound(args) To UBound(args)    ' перебираем все параметры фильтрации
        If Not IsMissing(args(i&)) Then
            If args(i&) Like "#*=*" Then ' распознаем параметры фильтрации
                FiltersCount& = FiltersCount& + 1
                Filters(FiltersCount&, 1) = Val(Split(args(i&), "=")(0)) ' столбец массива
                Filters(FiltersCount&, 2) = Split(args(i&), "=", 2)(1) ' маска для значения
            Else ' неверно заданный фильтр
                Debug.Print "ArrAutofilterNew error: invalid filter «" & args(i&) & "»"
            End If
        End If
    Next i&
    If FiltersCount& = 0 Then Debug.Print "Array filtering error: all filters are empty": Exit Function
  
    ReDim arrCheck(LBound(arr, 1) To UBound(arr, 1)) As Boolean ' для результатов проверки
    For i = LBound(arr, 1) To UBound(arr, 1)    ' перебираем все строки массива, и проверяем их
        arrCheck(i) = True
        For j& = 1 To FiltersCount&    ' перебираем все параметры фильтрации
            If Not (arr(i, Filters(j&, 1)) Like Filters(j&, 2)) Then arrCheck(i) = False: Exit For
        Next j&
        RowsCount& = RowsCount& - arrCheck(i) ' увеличиваем счётчик подходящих строк на 1
    Next i
    If RowsCount& = 0 Then Exit Function ' выход, если нет ни одной подходящей строки в массиве
     
    ReDim newarr(1 To RowsCount&, LBound(arr, 2) To UBound(arr, 2)) ' формируем новый массив
    For i = LBound(arr, 1) To UBound(arr, 1)    ' снова перебираем все строки массива
        If arrCheck(i) Then ' если строка ранее помечена как подходящая
            ro& = ro& + 1 ' вычисляем номер строки в новом массиве
            If rFirst = 0 Then rFirst = i
            For j = LBound(arr, 2) To UBound(arr, 2)
                newarr(ro&, j) = arr(i, j) ' заполняем массив значениями из исходного
            Next j
        End If
    Next i
    ArrAutofilterNew = newarr ' возвращаем результат
    Erase arrCheck
End Function
Извлечь дополнительные данные из функции пользователя
 
Вариант 1. Передать через аргумент функции.
Код
Private Sub CommandButton1_Click()
    x = Range("A1:J" & Cells(Rows.Count, 1).End(xlUp).Row).Value
    
    For i = 1 To UBound(x) 'расчет номера 1 строки реестра
        If x(i, 1) = "ГНН-0001" And CDate(x(i, 3)) = #1/1/2023# Then Exit For
    Next i
                    
    Dim rFirst As Long
                    
    With Cells(i, 1).Resize(UBound(ArrAutofilterNew(x, rFirst, "1=" & "ГНН-0001", "3=" & #1/1/2023#)), 10).Interior
    'раскраска ячеек
    End With
    Debug.Print rFirst
    
End Sub

Function ArrAutofilterNew(ByRef arr, rFirst As Long, ParamArray args() As Variant) As Variant   ' Новая версия функции ArrAutofilter, от января 2021 года.  © ExcelVBA.ru
    ' Получает по ссылке массив ARR для фильтрации
    ' и список критериев фильтрации в формате "3=маска текста" (номер столбца, "=", искомое значение)
    ' Возвращает двумерный массив с подходящими строками
     
    On Error Resume Next
    ArrAutofilterNew = False ' возвращаемое значение в случае ошибки
    If UBound(args) = -1 Then Debug.Print "Array filtering error: filters required": Exit Function
    ReDim Filters(1 To UBound(args) + 1, 1 To 2)
  
    Dim i&, ColumnToCheck&, FiltersCount&, j&, ro&, RowsCount&:  Err.Clear: i& = UBound(arr, 2)
    If Err.Number > 0 Then Debug.Print "Array filtering error: two dimensional array required": Exit Function
  
    For i& = LBound(args) To UBound(args)    ' перебираем все параметры фильтрации
        If Not IsMissing(args(i&)) Then
            If args(i&) Like "#*=*" Then ' распознаем параметры фильтрации
                FiltersCount& = FiltersCount& + 1
                Filters(FiltersCount&, 1) = Val(Split(args(i&), "=")(0)) ' столбец массива
                Filters(FiltersCount&, 2) = Split(args(i&), "=", 2)(1) ' маска для значения
            Else ' неверно заданный фильтр
                Debug.Print "ArrAutofilterNew error: invalid filter «" & args(i&) & "»"
            End If
        End If
    Next i&
    If FiltersCount& = 0 Then Debug.Print "Array filtering error: all filters are empty": Exit Function
  
    ReDim arrCheck(LBound(arr, 1) To UBound(arr, 1)) As Boolean ' для результатов проверки
    For i = LBound(arr, 1) To UBound(arr, 1)    ' перебираем все строки массива, и проверяем их
        arrCheck(i) = True
        For j& = 1 To FiltersCount&    ' перебираем все параметры фильтрации
            If Not (arr(i, Filters(j&, 1)) Like Filters(j&, 2)) Then arrCheck(i) = False: Exit For
        Next j&
        RowsCount& = RowsCount& - arrCheck(i) ' увеличиваем счётчик подходящих строк на 1
    Next i
    If RowsCount& = 0 Then Exit Function ' выход, если нет ни одной подходящей строки в массиве
     
    ReDim newarr(1 To RowsCount&, LBound(arr, 2) To UBound(arr, 2)) ' формируем новый массив
    For i = LBound(arr, 1) To UBound(arr, 1)    ' снова перебираем все строки массива
        If arrCheck(i) Then ' если строка ранее помечена как подходящая
            ro& = ro& + 1 ' вычисляем номер строки в новом массиве
            If rFirst = 0 Then rFirst = i
            For j = LBound(arr, 2) To UBound(arr, 2)
                newarr(ro&, j) = arr(i, j) ' заполняем массив значениями из исходного
            Next j
        End If
    Next i
    ArrAutofilterNew = newarr ' возвращаем результат
    Erase arrCheck
End Function
Удаление значения при вводе числа в другую ячейку, Ввод данных в таблицу
 
Код
Private Sub Worksheet_Change(ByVal Target As Range)
    If Target.Cells.CountLarge > 1 Then Exit Sub
    If Target.Row = 1 Then Exit Sub
    If Target.Column <> 3 Then Exit Sub
    If Not IsNumeric(Target.Value) Then Exit Sub
    Target.EntireRow.Cells(1, 4).Value = Date
    Target.EntireRow.Cells(1, 7).ClearContents
End Sub
Удаление значения при вводе числа в другую ячейку, Ввод данных в таблицу
 
Начните отсюда: Создание макросов и пользовательских функций на VBA
Удаление значения при вводе числа в другую ячейку, Ввод данных в таблицу
 
Правый клик на ярлычке листа - Исходный текст
Код
Private Sub Worksheet_Change(ByVal Target As Range)
    If Target.Cells.CountLarge > 1 Then Exit Sub
    If IsNumeric(Target.Value) Then Target.Cells(1, 2).ClearContents
End Sub
Вариант названия темы:
Удаление значения при вводе числа в другую ячейку.
Изменено: МатросНаЗебре - 13.02.2026 16:26:22
Страницы: 1 2 3 4 5 6 7 8 9 10 11 ... 300 След.
Наверх