繁体   English   中英

C# - 在Foreach循环中重用变量

[英]C# - reusing variable in Foreach loop

我想要做的就是找到一个连续的数字(Excel中的行号)的团体List ,并连续号码中的各个块,删除行集体 ,而不是一个在时刻,因为我有时会通过高达9K被迭代行和增长。 我遇到的问题是我调整foreach循环的方式,我需要重用已检查的最后一个非连续变量。

例如:列表是行{23,22,21,17,16,15}我需要拉出23-21,然后是17-15,然后删除块(这就是为什么它们按降序排列,从自下而上)。 循环进入17上的!= if语句,并且有效,但是已经使用了17并且16是循环的下一次迭代,因此17从未被捕获为下一个连续编号分组的开始。

我的问题:有没有办法以这种方式坚持17,以及新连续组的任何其他开始,还是我咆哮错误的树?

码:

public void FindMatchingBlocks(string stateId, string[] rangeNames)
    {
        Excel.Worksheet wksht = wkbk.Sheets["Sheet1"];
        Excel.Range rng = wksht.Range["$A$15:$A$23"];
        string val;
        string val2;
        List<int>rowNums = new List<int>();
        string rngStart = rangeNames[0].ToString(); //gives me "$A$15"
        string rngEnd = rangeNames[1].ToString();//gives me $A$23$
        string[] tempArray = rngEnd.Split('$');
        string end = tempArray[2].ToString();
        List<int> rowsToDelete = new List<int>(); 

        foreach (Excel.Range range in rng)
        {
            if (range.Row < Convert.ToInt32(end)+1) 
            {
                //pulls out the first two characters of the cell value to
                // match it to the stateID, if they match they are not to
                // be added to the list and not be deleted.
                val = range.Value.ToString();
                val2 = val.Substring(0, 2);

                if (Convert.ToInt32(val2) != Convert.ToInt32(stateId))
                {
                    rowsToDelete.Add(range.Row); // ends up being 
                                                 // {23,22,21,17,16,15}
                }                                       
            }
        }

        int count = 0;
        int firstItem = 0;
        rowsToDelete.Reverse();  //delete from the bottom up

        foreach (int x in rowsToDelete)
        {
            // First value in the ordered list: start of a sequence
            if (count == 0)
            {
                firstItem = x; 
                count = 1; 
            }
            // Skip duplicate values
            else if (x == firstItem - count)
            {
                count++;
            }
            // New value contributes to sequence
            else if (x != firstItem - count)
            {
                int endRow = firstItem;
                int startRow = firstItem - count + 1;
                Excel.Range delRange = wksht.Rows[startRow.ToString() + ":" + endRow.ToString()];
                delRange.Delete(Excel.XlDeleteShiftDirection.xlShiftUp);
                count = 0;
                firstItem = ????;  //can I do something to keep the first 
                                   //non-consecutive number each time it is
                                   // encountered.  In this list it skips 17
            }
        }
    }

希望这很清楚,带我去了解如何简明扼要地解释我需要什么。 谢谢。

我们有什么? 一系列整数。

我们想要什么? 整数范围的序列。

首先在类型系统中表示。 我们有一个整数序列的IEnumerable<int> 让我们做一个小类型:(在这里使用C#6表示法)

struct MyRange
{
    public int High { get; }
    public int Low { get; }
    public MyRange(int high, int low) : this() 
    {
        High = high;
        Low = low;
    }
}

简单。 我们方法的签名是什么? 我们想要整数和范围,所以:

static class MyExtensions 
{
  public static IEnumerable<MyRange> DescendingChunks(this IEnumerable<int> items)

似乎合理。 现在这件事做了什么? 有三种情况。 要么我们没有任何范围,因为我们是第一个,或者我们正在扩展当前范围,或者我们有一个新的范围。 每个案例都有一个案例:

{
    bool first = true;
    int high = 0;
    int low = 0;
    foreach(int item in items)
    {
        if (first)
        {
            high = item;
            low = item;
            first = false;
        }
        else if (item == low - 1)
        {
            low = item;
        }
        else
        {
            yield return new MyRange(high, low);
            high = item;
            low = item;
        }
    }

而且我们从未在序列中产生最后的东西......

    yield return new MyRange(high, low);
}

说得通? 而不是你的循环

foreach (int x in rowsToDelete)

我们有

foreach(MyRange range in rowsToDelete.DescendingChunks())

现在您知道要修改的范围。

超级红利问题:还有一个我没有列举的案例,因此这个方法存在一个小错误。 它是什么?

花了一些时间,但我能够想出一个紧凑的方法来获取一个数字列表找到连续的数字并将它们分组到一个列表中。 希望如果有人发现这个并且它有用:

private void groupConsecutiveNumbers()
    {
        /* this could easily be changed to look for ascending numbered groups by switching some of the "-1" to "+1"
     * and swapping the firstNum/endNum variables. */  


        int[] numArray = new int[]{ 50, 23, 22, 21, 15, 16, 14, 9, 5, 4, 3, 1};


        int firstNum = 0;
        int endNum = 0;            
        string grouping;

        for (int i = 0; i < numArray.Length; i++)
        {

        //If there is only 1 member of the list, that will be the first and last member of the group
    if (numArray.Length == 1) 
            {
                firstNum = numArray[0];
                endNum = numArray[0];
                grouping = firstNum.ToString() + "-" + endNum.ToString();
                lstGroups.Items.Add(grouping);
            }

    //if the number is the first one in the list then it automatically is the first one in the first list
            else if (i == 0) 
            {
                firstNum = numArray[0];
            }

    /* if its not the first one in the list and it is equal to the previous list item minus one
     * (contiguously descending), then enter this loop */
            else if (numArray[i] == (numArray[i-1] - 1)) 
            {

        //if this is the last member of the list, it automatically is the last item in the range
        if ((i + 1) == numArray.Length)
                {
                    endNum = numArray[i];
                    grouping = firstNum.ToString() + "-" + endNum.ToString();
                    lstGroups.Items.Add(grouping);
                }

        //if this isn't the last member of the list, exit the loop and continue with the next item.
                else
                {
                    continue;
                }
            }

    /* if the item if its not the first one in the list and does NOT equal the last item minus one 
     * (not contiguously descending) then the previous item was the last contiguously descending 
             * item and the current item is the first item in the next group */
            else if (numArray[i] != (numArray[i-1]-1))
            {
                endNum = numArray[i - 1];
                grouping = firstNum.ToString() + "-" + endNum.ToString();
                lstGroups.Items.Add(grouping);
                firstNum = numArray[i];
                endNum = 0;
            }

    /* After all that testing,if the item is the last item in the list AND the first number in the group
     * is also the last item in the list then the current item in the list is both the first and last member
     * in the current group. */
            if ((i + 1) == numArray.Length && firstNum == numArray[i])
            {
                endNum = numArray[i];
                grouping = firstNum.ToString() + "-" + endNum.ToString();
                lstGroups.Items.Add(grouping);
            }
        }
    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM