我有以下函数正在调用自身(递归)。目标是返回格式为filename(1).ext,filename(2).ext等的唯一文件名。
Function CreateUniqueFileName(strPath As String, strFileName, orderId As Integer) As String
Dim extPos As Integer
Dim extension As String
Dim fileName As String
fileName = ""
extPos = InStrRev(strFileName, ".")
If (extPos > 0) Then
fileName = Left(strFileName, extPos - 1)
extension = Right(strFileName, Len(strFileName) - extPos)
If (orderId = 0) Then
fileName = strFileName
CreateUniqueFileName = fileName
Else
fileName = fileName & " (" & CStr(orderId) & ")." & extension
End If
If (DoesFileExist(strPath & fileName)) Then
Call CreateUniqueFileName(strPath, fileName, orderId + 1)
Else
CreateUniqueFileName = fileName
Exit Function
End If
End If
End Function
如果是第一次调用,并且orderId值为0,则始终是第一个,因此是唯一的。因此,在这种情况下,该函数仅被调用一次。但是,当执行递归并且DosFileExists返回false时,返回值应该返回生成的文件名并退出。但是,当我调试该函数时,没有错误,但是它总是返回原始值,而不是原始迭代的结果。
例如,如果我这样调用此函数:CreateUniqueFileName(“ C:\ Temp \”,“” 1010-40-800.jpg“,1) 它会在 C:\ temp 中检查是否已经存在一个名为1010-40-800(1).jpg的文件,如果是的话,将调用相同的函数并将orderId更新为1(在这种情况下为CreateUniqueFileName) (“ C:\ Temp \”,“” 1010-40-800.jpg“,2)。重复相同的过程(回溯)。现在假设 1010-40-800(2).jpg 是唯一的(找不到文件)。我希望函数以字符串结果的形式返回 1010-40-800(2).jpg ,但是它将返回值
1010-40-800(1).jpg 。这实际上是第一次调用该函数的值。我在这里想念什么?
答案 0 :(得分:1)
当递归调用函数时,您的代码中只有一个小缺陷。试试这个
d = d.astype({'b': 'category'}).groupby('a').agg({'b':lambda x: x.iat[0], 'c':['mean', 'max']})
print(d)
b c
<lambda> mean max
a
1 1 1.5 2
2 2 3.5 4
这仍然不能满足您的要求,因为它会附加每个orderID,但您应该会发现该漏洞,并希望能够解决其余问题。
我使用以下功能检查文件是否存在
Function CreateUniqueFileName(strPath As String, strFileName, orderId As Integer) As String
Dim extPos As Integer
Dim extension As String
Dim fileName As String
fileName = ""
extPos = InStrRev(strFileName, ".")
If (extPos > 0) Then
fileName = Left(strFileName, extPos - 1)
extension = Right(strFileName, Len(strFileName) - extPos)
If (orderId = 0) Then
fileName = strFileName
CreateUniqueFileName = fileName
Else
fileName = fileName & " (" & CStr(orderId) & ")." & extension
End If
If (DoesFileExist(strPath & fileName)) Then
CreateUniqueFileName = CreateUniqueFileName(strPath, fileName, orderId + 1)
Else
CreateUniqueFileName = fileName
'Exit Function
End If
End If
End Function
但是在这种情况下,IMO会更适合获得唯一文件名的循环。
更新:查找附带的用于递归调用的完全固定版本和“循环”版本
Function DoesFileExist(fullFileName As String) As Boolean
Dim TestStr As String
TestStr = ""
On Error Resume Next
TestStr = Dir(fullFileName)
On Error GoTo 0
If TestStr = "" Then
DoesFileExist = False
Else
DoesFileExist = True
End If
End Function
以及带有循环的版本
Function CreateUniqueFileName(strPath As String, strFileName, orderID As Integer) As String
Dim extPos As Integer
Dim extension As String
Dim fileName As String
Dim resFilename As String
extPos = InStrRev(strFileName, ".")
If (extPos > 0) Then
fileName = Left(strFileName, extPos - 1)
extension = Right(strFileName, Len(strFileName) - extPos)
If (orderID = 0) Then
resFilename = strFileName
Else
resFilename = fileName & " (" & CStr(orderID) & ")." & extension
End If
If (DoesFileExist(strPath & resFilename)) Then
CreateUniqueFileName = CreateUniqueFileName(strPath, strFileName, orderID + 1)
Else
CreateUniqueFileName = resFilename
End If
End If
End Function
答案 1 :(得分:1)
您的代码存在结构,逻辑和假设方面的问题。
结构问题是,用于拆分扩展名的代码包含您的递归调用,因此,如果文件名不包含扩展名,则将永远不会发生递归。如果这是一个故意的决定,那么最好尽早退出该功能,而不是将其他所有内容包含在if结束条件中。
您的逻辑错误是您没有正确使用函数的递归调用
Call CreateUniqueFileName(strPath, fileName, orderId + 1)
应该是
CreateUniqueFileName = CreateUniqueFileName(strPath, fileName, orderId + 1)
您的假设问题是函数的参数是值。他们不是。默认情况下,VBA通过引用传递参数,因此每次调用函数时,在代码“文件名”中都是相同的变量,而不是成为新副本。
因此一行
fileName = fileName & " (" & CStr(orderId) & ")." & extension
在使用文件名而不是strFilename进行递归时,只会导致文件名问题。
我已经对您的代码进行了重组,以使递归部分更整洁(尽管其他人认为最好使用循环)
Function CreateUniqueFileName(ByVal StrPath As String, ByVal strFileName, ByRef orderId As Integer) As String
Dim FileNameArray As Variant
FileNameArray = Split(strFileName, ".")
If Len(FileNameArray(1)) = 0 Then
Debug.Print ("CreateUniqueFilename says strFilename has no extension")
CreateUniqueFileName = vbNullString
Exit Function
End If
If orderId = 0 Then
CreateUniqueFileName = FileNameArray(0) & Format(orderId, "0000") & FileNameArray(1)
Exit Function
End If
CreateUniqueFileName = GetUniqueName(StrPath, FileNameArray, orderId)
End Function
Public Function GetUniqueName(ByRef StrPath As String, ByRef FileNameArray As Variant, ByVal orderId As Integer) As String
' StrPath and FIlenamearray are passed by reference as they don't change during the recursion
' orderid is passed by value so that we don't change the value of orderid in the calling code.
' If this side effect is desired, change the ByVal to ByRef
Dim myFilename As String
myFilename = FileNameArray(0) & Format(orderId, "0000") & FileNameArray(1)
If (DoesFileExist(StrPath & myFilename)) Then
GetUniqueName = GetUniqueName(StrPath, FileNameArray, orderId + 1)
Else
GetUniqueName = myFilename
End If
End Function
请注意,我没有运行上面的代码,但可以正常编译。