Number balancer

flammabubble

New Member
Joined
Aug 19, 2015
Messages
24
Hey all,

Lets say I have the following 12 numbers:
1082
1043
1010
1002
1000
1000
995
992
985
984
980
974


I'm looking to find/build a tool within excel which will 'balance' those numbers into two groups of 6 with as close an average as possible. Does anyone have any suggestions as to how I would go about doing this?
 
Last edited:

Excel Facts

Which lookup functions find a value equal or greater than the lookup value?
MATCH uses -1 to find larger value (lookup table must be sorted ZA). XLOOKUP uses 1 to find values greater and does not need to be sorted.
What do you mean "balance"? with the numbers given, what result would you want?

Balance as in, group those numbers into two groups of 6, where the average of each group is as close to even as possible.

Using those numbers it would be something like:
1082
1002
995
985
984
974
Average =1003.66

1043
1010
1000
1000
992
980

Average = 1004.16
 
Upvote 0
So you want the groups split so that their averages are as equal as possible.
Must it be a 6/6 split?
 
Upvote 0
So you want the groups split so that their averages are as equal as possible.
Must it be a 6/6 split?

Yes that's right. And yes it will need to be an even split. Currently I don't have a better way to do this other than adding all the numbers together, dividing by two and then doing my best to reach that number on each team, so any better way than that would be helpful!
 
Upvote 0
If your values are in A1:A12 and you put this in a module, it should do what you want.
Note that Choices is a module wide variable and it declaration line should be outside of any procedure.
VBA Code:
Dim Choices As Variant

Sub test()
    Dim arrInput As Variant, workArray As Variant
    Dim targetVal As Double
    Dim currentVal As Double, currentResult As Variant, workVal As Double
    Dim arrResult1() As Double, arrResult2() As Double
    Dim i As Long, Size As Long, Point1 As Long, Point2 As Long
    
    arrInput = Application.Transpose(Range("A1:A12").Value)
    targetVal = WorksheetFunction.Sum(arrInput) / 2
    currentVal = 9E+99
    Size = UBound(arrInput)
    ReDim Choices(1 To Size)
    For i = 1 To Size
        Choices(i) = (i <= Size / 2)
    Next i
    
    Do
        workVal = 0
        For i = 1 To Size
            If Choices(i) Then
            workVal = workVal + arrInput(i)
            End If
        Next i
        If Abs(workVal - targetVal) < currentVal Then
            currentVal = Abs(workVal - targetVal)
            currentResult = Choices
        End If
        DoEvents
    Loop Until NextChoice
    
    ReDim arrResult1(1 To Size / 2): Point1 = 0
    ReDim arrResult2(1 To Size / 2): Point2 = 0
    For i = 1 To Size
        If currentResult(i) Then
            Point1 = Point1 + 1
            arrResult1(Point1) = arrInput(i)
        Else
            Point2 = Point2 + 1
            arrResult2(Point2) = arrInput(i)
        End If
    Next i
    Range("B1:B6").Value = Application.Transpose(arrResult1)
    Range("C1:C6").Value = Application.Transpose(arrResult2)
End Sub

Function NextChoice(Optional ByRef OverFlow As Boolean) As Boolean
    Dim lookAt As Long, WriteTo As Long
    Dim arrResult As Variant
   
    
    arrResult = Choices
    lookAt = 1
    Do Until arrResult(lookAt)
        lookAt = lookAt + 1
    Loop
    
    Do
        If arrResult(lookAt) Then
            WriteTo = WriteTo + 1
             
             arrResult(lookAt) = False
             arrResult(WriteTo) = True
             lookAt = lookAt + 1
        Else
            Rem done
            arrResult(WriteTo) = False
            arrResult(lookAt) = True
            Exit Do
        End If
    Loop Until UBound(arrResult) < lookAt
    OverFlow = (UBound(arrResult) <= lookAt)
    
    Choices = arrResult
    NextChoice = OverFlow
End Function
 
Upvote 0
I mean... that's pretty amazing - seems to work perfectly. I can't figure out what it's doing to actually calculate this though, is it just brute forcing until it gets the smallest gap between the averages?
 
Upvote 0
If you like some randomness:
My Monte Carlo simulation sbTeamGolf can help, I think:
 
Upvote 0
If your values are in A1:A12 and you put this in a module, it should do what you want.
Note that Choices is a module wide variable and it declaration line should be outside of any procedure.
VBA Code:
Dim Choices As Variant

Sub test()
    Dim arrInput As Variant, workArray As Variant
    Dim targetVal As Double
    Dim currentVal As Double, currentResult As Variant, workVal As Double
    Dim arrResult1() As Double, arrResult2() As Double
    Dim i As Long, Size As Long, Point1 As Long, Point2 As Long
   
    arrInput = Application.Transpose(Range("A1:A12").Value)
    targetVal = WorksheetFunction.Sum(arrInput) / 2
    currentVal = 9E+99
    Size = UBound(arrInput)
    ReDim Choices(1 To Size)
    For i = 1 To Size
        Choices(i) = (i <= Size / 2)
    Next i
   
    Do
        workVal = 0
        For i = 1 To Size
            If Choices(i) Then
            workVal = workVal + arrInput(i)
            End If
        Next i
        If Abs(workVal - targetVal) < currentVal Then
            currentVal = Abs(workVal - targetVal)
            currentResult = Choices
        End If
        DoEvents
    Loop Until NextChoice
   
    ReDim arrResult1(1 To Size / 2): Point1 = 0
    ReDim arrResult2(1 To Size / 2): Point2 = 0
    For i = 1 To Size
        If currentResult(i) Then
            Point1 = Point1 + 1
            arrResult1(Point1) = arrInput(i)
        Else
            Point2 = Point2 + 1
            arrResult2(Point2) = arrInput(i)
        End If
    Next i
    Range("B1:B6").Value = Application.Transpose(arrResult1)
    Range("C1:C6").Value = Application.Transpose(arrResult2)
End Sub

Function NextChoice(Optional ByRef OverFlow As Boolean) As Boolean
    Dim lookAt As Long, WriteTo As Long
    Dim arrResult As Variant
  
   
    arrResult = Choices
    lookAt = 1
    Do Until arrResult(lookAt)
        lookAt = lookAt + 1
    Loop
   
    Do
        If arrResult(lookAt) Then
            WriteTo = WriteTo + 1
            
             arrResult(lookAt) = False
             arrResult(WriteTo) = True
             lookAt = lookAt + 1
        Else
            Rem done
            arrResult(WriteTo) = False
            arrResult(lookAt) = True
            Exit Do
        End If
    Loop Until UBound(arrResult) < lookAt
    OverFlow = (UBound(arrResult) <= lookAt)
   
    Choices = arrResult
    NextChoice = OverFlow
End Function

Hi again, I was looking at transferring the sheet to google drive so I can run this from my phone but it doesn't look like there's any way to transfer excel script to google without completely redoing it. Is there any chance you know how to make this usable in google sheets? If not would you be able to break down the different sections so that I can try to rewrite it myself? Thanks!
 
Upvote 0

Forum statistics

Threads
1,215,327
Messages
6,124,280
Members
449,149
Latest member
mwdbActuary

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top