Excel 为每个循环变量更新

Excel 为每个循环变量更新,excel,vba,dictionary,for-loop,Excel,Vba,Dictionary,For Loop,其目的是找出c列中的值与从更新的“firstvalue”变量(以逗号分隔并存储在“M”列)中获得的所有值之间的循环度 此代码适用于初始firstvalue,任何人都可以建议任何方法来迭代更新后的第一个值。我不确定是否完全理解您的目标,但此代码应该可以找到每个任务的所有前置项: Sub circular() Dim sh As Worksheet Dim rTask As Range Dim oCell As Range Dim oFound As Range Dim lr As Long, j

其目的是找出c列中的值与从更新的“firstvalue”变量(以逗号分隔并存储在“M”列)中获得的所有值之间的循环度


此代码适用于初始firstvalue,任何人都可以建议任何方法来迭代更新后的第一个值。

我不确定是否完全理解您的目标,但此代码应该可以找到每个任务的所有前置项:

Sub circular()
Dim sh As Worksheet
Dim rTask As Range
Dim oCell As Range
Dim oFound As Range
Dim lr As Long, j As Long
Dim aPredecessors As Variant
Dim sCurTask As String
Dim secondValue As String
    Set sh = ThisWorkbook.Worksheets("Sheet1")
    lr = sh.Range("C" & Rows.Count).End(xlUp).Row
    Set rTask = sh.Range("C5:C" & lr)
    
    For Each oCell In rTask
        sCurTask = Trim(oCell.Text)
        aPredecessors = getPredecessors(Trim(oCell.Offset(0, 10).Text))
        j = LBound(aPredecessors)
        Do Until j > UBound(aPredecessors)
            secondValue = aPredecessors(j)
            If sCurTask = secondValue Then
                ReDim Preserve aPredecessors(j)
                Debug.Print "Task '" & sCurTask & "': Cyclic link '" & secondValue & "' for '" & Join(aPredecessors, ",") & "'!"
                aPredecessors(j) = aPredecessors(j) & " !!!"
            Else
                If secondValue <> vbNullString Then
                    Set oFound = rTask.Find(secondValue, LookIn:=xlValues)
                    If oFound Is Nothing Then
                        ReDim Preserve aPredecessors(j)
                        Debug.Print "Task '" & sCurTask & "': Task '" & secondValue & "' for '" & Join(aPredecessors, ",") & "' not found!"
                        aPredecessors(j) = aPredecessors(j) & " ???"
                    Else
                        Call addNewTasks(aPredecessors, Trim(oFound.Offset(0, 10).Text))
                    End If
                End If
            End If
            j = j + 1
        Loop
        oCell.Offset(0, 11).Value = Join(aPredecessors, ",")
    Next oCell
End Sub

Function getPredecessors(sPredecessors As String)
Dim i As Long
Dim aTemp As Variant, sRes As String
Dim sTest As String
    sRes = vbNullString
    aTemp = Split(sPredecessors, ",")
    For i = LBound(aTemp) To UBound(aTemp)
        sTest = Trim(aTemp(i))
        If InStr("," & sRes & ",", "," & sTest & ",") = 0 Then sRes = sRes & sTest & ","
    Next i
    If Len(sRes) > 1 Then sRes = Left(sRes, Len(sRes) - 1)
    getPredecessors = Split(sRes, ",")
End Function

Sub addNewTasks(aData As Variant, sPredecessors As String)
Dim i As Long, uB As Long
Dim aTemp As Variant
Dim sTest As String, sValid As String
    aTemp = Split(sPredecessors, ",")
    If UBound(aTemp) >= 0 Then ' Not empty
        sValid = "," & Join(aData, ",") & ","
        For i = LBound(aTemp) To UBound(aTemp)
            sTest = Trim(aTemp(i))
            If sTest <> vbNullString Then
                If InStr(sValid, "," & sTest & ",") = 0 Then
                    uB = UBound(aData) + 1
                    ReDim Preserve aData(uB)
                    aData(uB) = sTest
                    sValid = "," & Join(aData, ",") & ","
                End If
            End If
        Next i
    End If
End Sub
次循环()
将sh设置为工作表
将rTask设置为范围
Dim oCell As系列
深度范围
变暗lr为长,j为长
Dim APREDECESSOR作为变型
将sCurTask设置为字符串
将第二个值设置为字符串
设置sh=ThisWorkbook.Worksheets(“Sheet1”)
lr=sh.Range(“C”和Rows.Count).End(xlUp).Row
设置rTask=sh范围(“C5:C”和lr)
对于rTask中的每个oCell
sCurTask=Trim(oCell.Text)
aPredecessors=GetPreferences(修剪(oCell.Offset(0,10.Text))
j=LBound(一个预处理器)
直到j>U绑定(一个访问器)
第二个值=一个预处理器(j)
如果sCurTask=secondValue,则
ReDim保留一个预处理器(j)
调试。打印“任务'”&sCurTask&“':循环链接'”&secondValue&“'for'”&Join(apredcessors,,”&“!”
apredcessors(j)=apredcessors(j)&“!!!”
其他的
如果secondValue vbNullString,则
查找集合=rTask.Find(secondValue,LookIn:=xlValues)
如果你什么都不是的话
ReDim保留一个预处理器(j)
Debug.Print“Task'”&sCurTask&“':Task'”&secondValue&“for'”&Join(apredcessors),“,”&“未找到!”
APREDECESSOR(j)=APREDECESSOR(j)和“?”
其他的
调用addnewtask(apredcessors,Trim(of ound.Offset(0,10.Text))命令)
如果结束
如果结束
如果结束
j=j+1
环
oCell.Offset(0,11).Value=Join(apredcessors,“,”)
下奥塞尔
端接头
函数getPreferences(作为字符串的spredeccessors)
我想我会坚持多久
Dim aTemp作为变量,sRes作为字符串
像弦一样的暗杆
sRes=vbNullString
aTemp=拆分(存储处理器,“,”)
对于i=LBound(aTemp)到UBound(aTemp)
sTest=修剪(aTemp(i))
如果InStr(“,”和sRes&“,”,“,”和sTest&“,”)=0,则sRes=sRes和sTest&“,”
接下来我
如果Len(sRes)>1,则sRes=Left(sRes,Len(sRes)-1)
GetPreferences=Split(sRes,“,”)
端函数
子addnewtask(aData作为变量,spredeccessors作为字符串)
暗我一样长,乌布一样长
Dim aTemp作为变体
Dim sTest作为字符串,sValid作为字符串
aTemp=拆分(存储处理器,“,”)
如果UBound(aTemp)>=0,则“不为空”
sValid=“,”&Join(aData),“,”&“
对于i=LBound(aTemp)到UBound(aTemp)
sTest=修剪(aTemp(i))
如果是空字符串,则
如果InStr(sValid,“,”和sTest&“,”)=0,则
uB=UBound(aData)+1
雷迪姆保存数据(uB)
aData(uB)=sTest
sValid=“,”&Join(aData),“,”&“
如果结束
如果结束
接下来我
如果结束
端接头

欢迎来到StackOverflow!请您用C列和M列的样本数据补充您的问题,以帮助我们了解您的目标。@Johnson谢谢您的回复,我现在附上了图片,请检查。谢谢,谢谢!所以,有了这些数据,你们会得到:对于C5-仍然没有,对于C6(2)-只有1,对于C7(4/6,7)-结果将是6,7,2,1,4,6,7,2,1。。。越来越多,越来越多,越来越多-一个无休止的循环,以计算机的空闲内存结束?@johnson是的,你说得对,但对于C7,前置列表包含4个,它也在任务列中。所以循环应该在这里停止。所有C值的处理过程类似。谢谢你,汉克!您是champ,但在debug.print中,我想找到of ound value,换句话说,of ound.offset(0,10).value,sCurTask存在,所以我将直接转到该值并更改该值,您认为可行吗?对于大数据集来说,该算法的时间复杂度非常大,换句话说,读取1000行数据需要5分钟,所以这个问题有任何补救措施吗?@Waqas当然有可能:我们可以创建到错误单元的直接链接,以便快速导航。例如,将HYPERLINK()函数放在oCell.Offset(0,12)中。我知道这个草稿远非理想,我只是想确保我正确地阅读了您的代码并理解了您的目的。这种算法可以而且应该改进。您是否需要按照找到相应任务的顺序列出前置任务?或者它可以按升序排列?有序结构(通常)可以节省大量时间,但代价是代码稍微复杂化。您好,是的,您完全理解我的观点,并且您的算法在我的情况下运行正常。但实际的目的是为每个任务创建一个前导链,并检查该链是否包含该任务,如果在debug.print“任务(我们为其制作链)和任务(在其m列中包含该任务)之间找到循环引用。将这些任务打印到工作表并不是必需的要求。只需找到异常情况并通过msgbox弹出。谢谢。我会尝试整洁地完成。但在我看来,msgbox不太适合1000行的大集合。如果只有5%的任务描述不正确,那么您将收到50个弹出窗口。我会考虑其他选择。是的,这是ri嗯,我认为另一种选择是,我们可以在每次弹出后使用exit sub命令,或者创建一个数组,然后在最后检查后在消息框中显示它。谢谢。
Sub circular()
Dim sh As Worksheet
Dim rTask As Range
Dim oCell As Range
Dim oFound As Range
Dim lr As Long, j As Long
Dim aPredecessors As Variant
Dim sCurTask As String
Dim secondValue As String
    Set sh = ThisWorkbook.Worksheets("Sheet1")
    lr = sh.Range("C" & Rows.Count).End(xlUp).Row
    Set rTask = sh.Range("C5:C" & lr)
    
    For Each oCell In rTask
        sCurTask = Trim(oCell.Text)
        aPredecessors = getPredecessors(Trim(oCell.Offset(0, 10).Text))
        j = LBound(aPredecessors)
        Do Until j > UBound(aPredecessors)
            secondValue = aPredecessors(j)
            If sCurTask = secondValue Then
                ReDim Preserve aPredecessors(j)
                Debug.Print "Task '" & sCurTask & "': Cyclic link '" & secondValue & "' for '" & Join(aPredecessors, ",") & "'!"
                aPredecessors(j) = aPredecessors(j) & " !!!"
            Else
                If secondValue <> vbNullString Then
                    Set oFound = rTask.Find(secondValue, LookIn:=xlValues)
                    If oFound Is Nothing Then
                        ReDim Preserve aPredecessors(j)
                        Debug.Print "Task '" & sCurTask & "': Task '" & secondValue & "' for '" & Join(aPredecessors, ",") & "' not found!"
                        aPredecessors(j) = aPredecessors(j) & " ???"
                    Else
                        Call addNewTasks(aPredecessors, Trim(oFound.Offset(0, 10).Text))
                    End If
                End If
            End If
            j = j + 1
        Loop
        oCell.Offset(0, 11).Value = Join(aPredecessors, ",")
    Next oCell
End Sub

Function getPredecessors(sPredecessors As String)
Dim i As Long
Dim aTemp As Variant, sRes As String
Dim sTest As String
    sRes = vbNullString
    aTemp = Split(sPredecessors, ",")
    For i = LBound(aTemp) To UBound(aTemp)
        sTest = Trim(aTemp(i))
        If InStr("," & sRes & ",", "," & sTest & ",") = 0 Then sRes = sRes & sTest & ","
    Next i
    If Len(sRes) > 1 Then sRes = Left(sRes, Len(sRes) - 1)
    getPredecessors = Split(sRes, ",")
End Function

Sub addNewTasks(aData As Variant, sPredecessors As String)
Dim i As Long, uB As Long
Dim aTemp As Variant
Dim sTest As String, sValid As String
    aTemp = Split(sPredecessors, ",")
    If UBound(aTemp) >= 0 Then ' Not empty
        sValid = "," & Join(aData, ",") & ","
        For i = LBound(aTemp) To UBound(aTemp)
            sTest = Trim(aTemp(i))
            If sTest <> vbNullString Then
                If InStr(sValid, "," & sTest & ",") = 0 Then
                    uB = UBound(aData) + 1
                    ReDim Preserve aData(uB)
                    aData(uB) = sTest
                    sValid = "," & Join(aData, ",") & ","
                End If
            End If
        Next i
    End If
End Sub