我的目标很简单,我正在尝试为数据库中的产品生成所有可能组合的列表。
所以例如;产品选项如下
我希望能够自动生成所有3个组合的每个组合:
Small, Red, Mens
Small, Green, Mens
Small, Blue, Mens
etc
无论我是否将2,3,4或5个数组传入其中,我都需要该函数。
我做了很多研究并发现了以下文章但却未能实现我的目标。
我发现的文章如下:
答案 0 :(得分:4)
在笛卡尔产品上调整Eric Lippert's blog的代码:
Private Function CartesianProduct(Of T)(ParamArray sequences As T()()) As T()()
' base case:
Dim result As IEnumerable(Of T()) = {New T() {}}
For Each sequence As var In sequences
Dim s = sequence
' don't close over the loop variable
' recursive case: use SelectMany to build the new product out of the old one
result = From seq In result
From item In s
Select seq.Concat({item}).ToArray()
Next
Return result.ToArray()
End Function
用法:
Dim s1 As String() = New String() {"small", "med", "large", "XL"}
Dim s2 As String() = New String() {"red", "green", "blue"}
Dim s3 As String() = New String() {"Men", "Women"}
Dim ss As String()() = CartesianProduct(s1, s2, s3)
答案 1 :(得分:0)
一个在另一个内部的三个循环应该可以解决问题。
所以伪代码......
For each value in sex array
For each value in size array
For each value in colour array
Output sex, size, colour values
Next colour
Next size
Next sex
更新了Pseudo
Sub ouputOptions(array1, array2, array3, array4, array5)
For each value in array1
For each value in array2
If array3 Not Nothing Then
For each value in array3
If array4 Not Nothing Then
For each value in array4
If array5 Not Nothing Then
For each value in array5
output array1, array2, array3, array4, array5 values
next array5
Else
Output array1, array2, array3, array4 values
End if
Next array4
Else
Output array1, array2, array3 values
End if
next array3
Else
Output array1, array2 values
End if
Next array2
Next array1
End Sub
您需要将数组3到5指定为Optional
答案 2 :(得分:0)
你可以通过一点递归来实现这一点。
以下结果返回一个字符串数组数组。
Public class Permuter
Public Function Permute(ParamArray toPermute As String()()) As String()()
Return DoPermute(Nothing, toPermute)
End Function
''' <summary>
''' Permute the first two arrays,then pass that, and the remainder recursively
''' </summary>
Private Function DoPermute(working As String()(), toPermute As String()()) As String()()
Dim nextWorking As String()()
If working Is Nothing Then
'Make a new working list
nextWorking = (From a In toPermute(0)
Select {a}).ToArray
Else
'Combine from the next working list
nextWorking = (From a In working, b In toPermute(0)
Select a.Concat({b}).ToArray).ToArray
End If
If toPermute.Length > 1 Then
'Go Around again
Dim nextPermute = toPermute.Skip(1).ToArray
Return DoPermute(nextWorking, nextPermute)
Else
'We're done
Return nextWorking
End If
End Function
End Class
将公共方法称为:
Dim permuter = New Permuter
Dim permutations = permuter.Permute({"a", "b", "c"}, {"1", "2", "3"}, {"x", "y", "z"})
更新:接受@DStanley的Eric Lippert博客参考,以下是that post上提到的累加器方法的转换:
Public Function CartesianProduct(Of T)(ParamArray sequences As T()()) As IEnumerable(Of IEnumerable(Of T))
Dim emptyProduct As IEnumerable(Of IEnumerable(Of T)) = {Enumerable.Empty(Of T)()}
Return sequences.Aggregate(
emptyProduct,
Function(accumulator, sequence) _
From accseq In accumulator, item In sequence
Select accseq.Concat({item})
)
End Function
请注意,这会返回延迟查询,而不是扩展的数组集。
答案 3 :(得分:0)
递归有时是错误的方法。
如果你不想使用递归(害怕StackOverflow异常?),你可以这样做:
List<List<string>> Combine(List<List<string>> lists)
{
List<List<string>> result = new List<List<string>>();
var arrayIndexes = new int[lists.Count];
result.Add(GetCurrentItem(lists, arrayIndexes));
while (!AllIndexesAreLast(lists, arrayIndexes))
{
for (int i = arrayIndexes.Length - 1; i >= 0; i--)
{
arrayIndexes[i] = (arrayIndexes[i] + 1) % lists[i].Count;
if (arrayIndexes[i] != 0)
{
break;
}
}
result.Add(GetCurrentItem(lists, arrayIndexes));
}
return result;
}
List<string> GetCurrentItem(List<List<string>> lists, int[] arrayIndexes)
{
var item = new List<string>();
for (int i = 0; i < lists.Count; i++)
{
item.Add(lists[i][arrayIndexes[i]]);
}
return item;
}
bool AllIndexesAreLast(List<List<string>> lists, int[] arrayIndexes)
{
for (int i = 0; i < arrayIndexes.Length; i++)
{
if (lists[i].Count - 1 != arrayIndexes[i])
{
return false;
}
}
return true;
}
你可以像这样使用它:
var shirts = new List<List<string>>()
{
new List<string>() {"colour", "red", "blue", "green", "yellow"},
new List<string>() {"cloth", "cotton", "poly", "silk"},
new List<string>() {"type", "full", "half"}
};
var result = Combine(shirts);
答案 4 :(得分:0)
(我认为)我需要完全相同的东西,但我无法在答案中找到我需要的东西(主要是因为它们是我不知道的语言,我猜)。 / p>
我带来了这个(功能本身):
Public Function nChooseK(Of T)(ByVal Values As List(Of T), ByVal k As Integer, Optional ByRef Result As List(Of List(Of T)) = Nothing, Optional ByRef CurCombination As List(Of T) = Nothing, Optional ByVal Offset As Integer = 0) As List(Of List(Of T))
Dim n = Values.Count
If CurCombination Is Nothing Then CurCombination = New List(Of T)
If Result Is Nothing Then Result = New List(Of List(Of T))
If k <= 0 Then
Result.Add(CurCombination.ToArray.ToList)
Return Result
Else
For i = Offset To n - k
CurCombination.Add(Values(i))
nChooseK(Values, k - 1, Result, CurCombination, i + 1)
CurCombination.RemoveAt(CurCombination.Count - 1)
Next
Return Result
End If
End Function
所有人需要做的就是将它放在一个模块中(或者在我猜的调用它的子/函数的上方/下方)并用任何变量和数字调用它
如何称呼它:
nChooseK(List, kInteger)
小例子:
Dim NumbersCombinations As List(Of List(Of Integer)) = nChooseK(lstNumbers, k)
与整数和字符串一起使用以及将结果打印到屏幕的完整示例:
Dim Numbers() As Integer = {1, 2, 3, 4, 5}
Dim lstNumbers = New List(Of Integer)
Dim k = 3
lstNumbers.AddRange(Numbers)
Dim NumbersCombinations As List(Of List(Of Integer)) = nChooseK(lstNumbers, k)
Dim sbCombinations1 As New StringBuilder
For i = 0 To NumbersCombinations.Count - 1
sbCombinations1.AppendLine()
For j = 0 To NumbersCombinations(i).Count - 1
sbCombinations1.Append(NumbersCombinations(i)(j) & " ")
Next
sbCombinations1.Length = sbCombinations1.Length - 1
Next
MsgBox(sbCombinations1.ToString)
Dim lstNoumera = New List(Of String)
lstNoumera.AddRange({"ena", "dio", "tria", "tessera", "pente"})
Dim Combinations As List(Of List(Of String)) = nChooseK(lstNoumera, k)
Dim sbCombinations2 As New StringBuilder
For i = 0 To Combinations.Count - 1
sbCombinations2.AppendLine()
For j = 0 To Combinations(i).Count - 1
sbCombinations2.Append(Combinations(i)(j) & " ")
Next
sbCombinations2.Length = sbCombinations2.Length - 1
Next
MsgBox(sbCombinations2.ToString)