我正在尝试使用类似于sum函数的公式。唯一的区别是,一旦它累加了3个(或更多)单元格的数量,它将在编辑另一个单元格时编辑某个单元格以保持该总值。
例如:
A,B和C列分别为3,并且等于9:
| A | B | C |...| Total |
+----+-----+----+...+-------+
| 3 | 3 | 3 |...| 9 |
A列和B列分别被编辑为等于2,但是我仍然希望将总数保持为9,因此我希望C列自动更改为5。
此:
| A | B | C |...| Total |
+----+-----+----+...+-------+
| 2 | 2 | 3 |...| 7 |
应更新为:
| A | B | C |...| Total |
+----+-----+----+...+-------+
| 2 | 2 | 5 |...| 9 |
之所以这样做,是因为它被发送到该国的多个地区,在那里仅需编辑2个单元格,但我希望保持总数而不用编辑2k +行的数据输入。
我也接受VBA选项。有人有什么想法吗?
答案 0 :(得分:1)
您可以找到问题here。
示例:
A,B和C列分别为3,并且等于9:
| A | B | C |...| Total |
+----+-----+----+...+-------+
| 3 | 3 | 3 |...| 9 |
A列和B列分别被编辑为等于2,但是我仍然希望将总数保持为9,因此我希望C列自动更改为5:
| A | B | C |...| Total |
+----+-----+----+...+-------+
| 2 | 2 | 3 |...| 7 |
我意识到我的代码有些混乱,因此将其分解为sheet1,模块main和名为CollectionOfGeneratedValues
的类。
您唯一需要在代码中调整的变量是
masterRange
,rangeToFill
中的列和sumTarget
中的列以适合您的数据输入。
快速浏览:
您必须在VBA中设置masterRange
或要使用的范围。在电子表格中,您必须为sumtarget
的每一行设置masterRange
。
当在您的masterRange
内的单元格中输入值时,我们将找出这是哪一行,并生成一个单独的范围即该行。
如果输入的金额大于sumTarget
,我们将Exit Sub
并责骂用户。
我们生成一个值的数组,其值以及用户输入将为sumtarget
。然后,我们采用总和目标并减去用户输入。
sumtarget.value
之间的随机数sumtarget
中减去其值。columnsInRange
进行了1次。 for loop
作为最后一个值时,我们将该值设置为sumtarget
剩余的值。Fisher-Yates Shuffle
,这样我们就不必始终将collection的值/电子表格的值降序更新:感谢您的评论,建议和帮助。我应该多考虑一下什么样的形式。我只剩下某种奇怪的动态/静态混合动力。一个自定义的UserForm可以生成这些集合,然后可以打印到工作表中,这真是太酷了。无论如何,我接受了雷斯塔法里安的大部分建议。我喜欢用其中的一些方法,例如在哪里存储输入检查逻辑。但是总的来说,他的建议是正确的。再次谢谢你。
第1页:
Option Explicit
Private Sub Worksheet_Change(ByVal target As Range)
SolveSudokuLite.Main target
End Sub
模块SolveSudokuLite
:
显式选项 子主要(ByRef目标为范围) 昏暗masterRange作为范围 昏暗rangeToFill作为范围 Dim valuesToFillRange作为GeneratedValuesCollection
Application.EnableEvents = False
Set masterRange = Range("B1:E5")
Set valuesToFillRange = New GeneratedValuesCollection
If Not Intersect(masterRange, target) Is Nothing Then
TargetSum.setTargetSum target
If Not IsValidInput(target) Then Exit Sub
valuesToFillRange.GenerateValues target
PrintValues valuesToFillRange, target
End If
Application.EnableEvents = True
End Sub
Function IsValidInput(ByVal target As Range) As Boolean
IsValidInput = True
If (target.value >= TargetSum.sum) Or Not IsNumeric(target.value) Then
MsgBox ("WILL NOT CALCULATE FOR ROW " & target.Row & ", USER INPUT INVALID")
IsValidInput = False
Application.EnableEvents = True
End If
End Function
Function PrintValues(ByRef valuesToFillRange As GeneratedValuesCollection, ByVal target As Range)
Dim rangeToFill As Range
Dim collectionCounter As Long
Dim cellInRangeToFill As Range
Set rangeToFill = Range("A" & target.Row & ":E" & target.Row)
collectionCounter = 1
For Each cellInRangeToFill In rangeToFill
If cellInRangeToFill.Address = target.Address Then
cellInRangeToFill.value = target.value
Else
cellInRangeToFill.value = valuesToFillRange.Item(collectionCounter)
collectionCounter = collectionCounter + 1
End If
Next cellInRangeToFill
End Function
名为GeneratedValuesCollection
的类:
Option Explicit
Private GeneratedValuesCollection As Collection
Private Sub Class_Initialize()
Set GeneratedValuesCollection = New Collection
End Sub
Private Sub Class_Terminate()
Set GeneratedValuesCollection = Nothing
End Sub
Public Property Get Count() As Long
Count = GeneratedValuesCollection.Count
End Property
Public Sub Add(num As Long)
GeneratedValuesCollection.Add num
End Sub
Public Property Get Item(Index As Variant) As Long
Item = GeneratedValuesCollection.Item(Index)
End Property
Public Sub Clear()
Set GeneratedValuesCollection = New Collection
End Sub
Public Sub GenerateValues(ByVal target As Range)
Dim userSetValue As Long
Dim sumLeft As Long
Dim numbersToGenerate As Long
userSetValue = target.value
sumLeft = SetInitialSumLeft(userSetValue)
numbersToGenerate = NumberValuesToGenerate(target)
SetValues numbersToGenerate, sumLeft
End Sub
Private Function SetInitialSumLeft(ByVal userSetValue As Long) As Long
SetInitialSumLeft = TargetSum.sum - userSetValue
End Function
Private Function NumberValuesToGenerate(ByVal target As Range) As Long
Dim rangeToFill As Range
Set rangeToFill = Range("A" & target.Row & ":E" & target.Row)
NumberValuesToGenerate = rangeToFill.Columns.Count - 1
End Function
Private Sub SetValues(ByVal numbersToGenerate As Long, ByVal sumLeft As Long)
Dim counter As Long
Dim value As Long
For counter = 1 To numbersToGenerate - 1
value = Application.WorksheetFunction.RandBetween(0, sumLeft / 1.25)
Me.Add value
sumLeft = sumLeft - value
Next counter
Me.Add sumLeft
End Sub
Public Sub ShuffleCollection()
Dim holdValuesArray As Collection
Set holdValuesArray = DuplicateCollection()
Swap holdValuesArray
End Sub
Private Function DuplicateCollection() As Collection
Dim counter As Long
Dim maxNum As Long
Set DuplicateCollection = New Collection
maxNum = Me.Count
For counter = 1 To maxNum
DuplicateCollection.Add Me.Item(counter)
Next counter
End Function
Private Sub Swap(ByRef holdValuesArray As Collection)
Dim randomNum As Long
Dim maxNum As Long
Dim counter As Long
Me.Clear
maxNum = holdValuesArray.Count
For counter = 1 To maxNum
randomNum = Application.WorksheetFunction.RandBetween(1, holdValuesArray.Count)
Me.Add (holdValuesArray(randomNum))
holdValuesArray.Remove (randomNum)
Next counter
End Sub
名为TargetSum
的类:
Option Explicit
Private CollectionOfGeneratedValues As Collection
Private Type TTargetSum
sum As Long
End Type
Private this As TTargetSum
Public Property Get sum() As Long
sum = this.sum
End Property
Public Sub setTargetSum(ByVal value As Range)
this.sum = Range("F" & value.Row)
End Sub