Introduction
In this tip, I will present an easy to use method for iterating over all permutations of a model. Each model parameter is defined as an entry into a Dictionary(of String, Object)
. Any number of model parameters can be used as input and the output is a Dictionary(of Integer, Object)
where the integer key is the permutation number and the object is another dictionary that contains the model parameters for that permutation. This is useful in providing every possible set of inputs into a function.
Background
Other permutation examples will give you every instance of a string
or integer array. What if your inputs are more complex? By using a Dictionary(of String, Object)
for model inputs, a name for the parameter can be defined and the parameters can be anything from a simple array, true
/false
values, a class, or a structure.
Using the Code
Examples here are in VB. Download for the C# project for C# code.
Use the code by defining a Dictionary(of String, Object)
inputs:
Dim d As New Dictionary(Of String, Object)
Dim b() As Boolean = {True, False}
d.Add("IsMarried", b)
d.Add("IsEmployed", b)
d.Add("YearsAtAddress", {2, 5, 10})
d.Add("IncomeLevel", {25000, 50000, 75000, 100000})
Dim cb As New List(Of Credit)
cb.Add(New Credit With {.Bureau = "Equifax", .ScoreAvg = 500})
cb.Add(New Credit With {.Bureau = "Equifax", .ScoreAvg = 600})
cb.Add(New Credit With {.Bureau = "Equifax", .ScoreAvg = 700})
cb.Add(New Credit With {.Bureau = "Transunion", .ScoreAvg = 500})
cb.Add(New Credit With {.Bureau = "Transunion", .ScoreAvg = 600})
cb.Add(New Credit With {.Bureau = "Transunion", .ScoreAvg = 700})
d.Add("Credit", cb)
Then call the function:
Dim ps As Dictionary(Of Integer, Object) = PermutateDictionary.Permutations(d)
The result is a dictionary containing all the permutations and the parameters for each.
1: True(IsMarried) True(IsEmployed) 2(YearsAtAddress) 25000(IncomeLevel) Equifax-500(Credit)
2: True(IsMarried) True(IsEmployed) 2(YearsAtAddress) 25000(IncomeLevel) Equifax-600(Credit)
3: True(IsMarried) True(IsEmployed) 2(YearsAtAddress) 25000(IncomeLevel) Equifax-700(Credit)
4: True(IsMarried) True(IsEmployed) 2(YearsAtAddress) 25000(IncomeLevel) Transunion-500(Credit)
5: True(IsMarried) True(IsEmployed) 2(YearsAtAddress) 25000(IncomeLevel) Transunion-600(Credit)
6: True(IsMarried) True(IsEmployed) 2(YearsAtAddress) 25000(IncomeLevel) Transunion-700(Credit)
7: True(IsMarried) True(IsEmployed) 2(YearsAtAddress) 50000(IncomeLevel) Equifax-500(Credit)
8: True(IsMarried) True(IsEmployed) 2(YearsAtAddress) 50000(IncomeLevel) Equifax-600(Credit)
9: True(IsMarried) True(IsEmployed) 2(YearsAtAddress) 50000(IncomeLevel) Equifax-700(Credit)
10: True(IsMarried) True(IsEmployed) 2(YearsAtAddress) 50000(IncomeLevel) Transunion-500(Credit)
11: True(IsMarried) True(IsEmployed) 2(YearsAtAddress) 50000(IncomeLevel) Transunion-600(Credit)
12: True(IsMarried) True(IsEmployed) 2(YearsAtAddress) 50000(IncomeLevel) Transunion-700(Credit)
13: True(IsMarried) True(IsEmployed) 2(YearsAtAddress) 75000(IncomeLevel) Equifax-500(Credit)
14: True(IsMarried) True(IsEmployed) 2(YearsAtAddress) 75000(IncomeLevel) Equifax-600(Credit)
15: True(IsMarried) True(IsEmployed) 2(YearsAtAddress) 75000(IncomeLevel) Equifax-700(Credit)
16: True(IsMarried) True(IsEmployed) 2(YearsAtAddress) 75000(IncomeLevel) Transunion-500(Credit)
17: True(IsMarried) True(IsEmployed) 2(YearsAtAddress) 75000(IncomeLevel) Transunion-600(Credit)
18: True(IsMarried) True(IsEmployed) 2(YearsAtAddress) 75000(IncomeLevel) Transunion-700(Credit)
19: True(IsMarried) True(IsEmployed) 2(YearsAtAddress) 100000(IncomeLevel) Equifax-500(Credit)
20: True(IsMarried) True(IsEmployed) 2(YearsAtAddress) 100000(IncomeLevel) Equifax-600(Credit)
21: True(IsMarried) True(IsEmployed) 2(YearsAtAddress) 100000(IncomeLevel) Equifax-700(Credit)
22: True(IsMarried) True(IsEmployed) 2(YearsAtAddress) 100000(IncomeLevel) Transunion-500(Credit)
23: True(IsMarried) True(IsEmployed) 2(YearsAtAddress) 100000(IncomeLevel) Transunion-600(Credit)
24: True(IsMarried) True(IsEmployed) 2(YearsAtAddress) 100000(IncomeLevel) Transunion-700(Credit)
.
.
.
281: False(IsMarried) False(IsEmployed) 10(YearsAtAddress) 75000(IncomeLevel) Transunion-600(Credit)
282: False(IsMarried) False(IsEmployed) 10(YearsAtAddress) 75000(IncomeLevel) Transunion-700(Credit)
283: False(IsMarried) False(IsEmployed) 10(YearsAtAddress) 100000(IncomeLevel) Equifax-500(Credit)
284: False(IsMarried) False(IsEmployed) 10(YearsAtAddress) 100000(IncomeLevel) Equifax-600(Credit)
285: False(IsMarried) False(IsEmployed) 10(YearsAtAddress) 100000(IncomeLevel) Equifax-700(Credit)
286: False(IsMarried) False(IsEmployed) 10(YearsAtAddress) 100000(IncomeLevel) Transunion-500(Credit)
287: False(IsMarried) False(IsEmployed) 10(YearsAtAddress) 100000(IncomeLevel) Transunion-600(Credit)
288: False(IsMarried) False(IsEmployed) 10(YearsAtAddress) 100000(IncomeLevel) Transunion-700(Credit)
The code to produce the output is:
For Each p In ps
Console.Write(CStr(p.Key) + ": ")
For Each e In p.Value
If TypeName(e.value) = "Credit" Then
Console.Write(CStr(e.value.Bureau + "-" + _
e.value.ScoreAvg.ToString) + "(" + e.key + ") ")
Else
Console.Write(CStr(e.value) + "(" + e.key + ") ")
End If
Next
Console.WriteLine()
Next
The code that does the work is:
Public Class PermutateDictionary
Shared Function Permutations(ds As Dictionary(Of String, Object)) _
As Dictionary(Of Integer, Object)
Dim pCount As Integer = 1
Dim sPointer As New Dictionary(Of String, Integer)
Dim pNumber As Integer
Dim result As New Dictionary(Of Integer, Object)
For Each d In ds
pCount *= GetEntryCount(d)
sPointer.Add(d.Key, 0)
Next
For pNumber = 1 To pCount
Dim pEntry As New Dictionary(Of String, Object)
For Each d In ds
pEntry.Add(d.Key, d.Value(sPointer(d.Key)))
Next
result.Add(pNumber, pEntry)
For Each d In ds.Reverse
sPointer(d.Key) += 1
If sPointer(d.Key) = GetEntryCount(d) Then
sPointer(d.Key) = 0
Else
Exit For
End If
Next
Next
Return result
End Function
Private Shared Function GetEntryCount(ByRef Entry As Object) _
As Integer
Try
Return Entry.Value.length
Catch ex As Exception
Return Entry.Value.count
End Try
End Function
End Class
Download the sample project. I hope you find this useful.