【问题标题】:Array iteration starting from the middle数组从中间开始迭代
【发布时间】:2010-12-09 15:59:23
【问题描述】:

在最近的一次采访中,有人问了一个奇怪的问题

a[]= { 1,2,3,4,5,6,7,8,9,10}

当给定一个具有指定起始索引的数组时,我必须迭代它直到我遍历 所有元素。

我的意思是假设起始索引是“5”我必须从6,7,8,9,10,5,4,3,2,1开始。请仔细查看序列,如何创建Reset(), 当前,等等,等等……?。

但面试官按照他的要求执行了序列。他没有显示代码。

我们真的可以为这种奇怪的需求开发逻辑吗?

【问题讨论】:

    标签: c# arrays iterator


    【解决方案1】:

    只需使用两个循环。

    IEnumerable<int> ForwardsBackwards(int[] a, int start) {
        for(int i=start; i<a.Length; i++) 
            yield return a[i];
        for(int i=start-1; i>=0; i--) 
            yield return a[i];
    }
    

    编辑: 使用 linq 会更好:

    IEnumerable<int> ForwardBackward(int[] a, int start) {
        return a.Skip(start).Concat(a.Take(start).Reverse());
    }
    

    【讨论】:

    • 哦!抱歉,我认为它是无效的问题。我们实际上可以实现它。
    • 我以为面试官问了一些讨厌的问题
    • 我认为“更好”的 LINQ 版本并没有那么好,因为它遍历数组两次(IIRC,SkipTake 实现都不会检查 IList优化)。
    • 如果这是一个讨厌的问题,我需要去做一些采访。
    【解决方案2】:

    更容易维护(?):

            int[] a= {1,2,3,4,5,6,7,8,9,10};
    
            int StartIndex=5;
    
            for (int iCount = StartIndex; iCount < a.Count() + StartIndex; iCount++)
            {
                Debug.WriteLine(a[(iCount + a.Count()) % a.Count()]);
            }
    

    输出是:

    6 7 8 9 10 1 2 3 4 5

    编辑:刚刚发现你的序列,当你达到上限时它会反转。如果这是指定的问题,那就太糟糕了。

    【讨论】:

    • 不提你已经注意到的输出错误的事实,索引内的 + a.Count() 是多余的,因为你然后执行 % a.Count()。
    • 正是我需要的,谢谢!我做得更进一步,让它双向工作,添加“运动”变量。在下面发布解决方案。
    【解决方案3】:

    这是一个旧线程,但我需要相同的算法,并找到了一个不错的解决方案。解决方案

    1. 可以从数组的任何元素开始
    2. 可以开始迭代到任何方向
    3. 将传递所有元素,从 NEXT 开始沿运动方向
    4. 当到达边框元素时,将与第一个/最后一个重叠

    所有的魔法都与 for 循环操作符单行,其他代码是为了方便预览。

    // Example program
    #include <iostream>
    #include <string>
    
    int a[] = {0,1,2,3,4,5};
    int Count = sizeof(a)/sizeof(int);
    
    void LoopFromMidWithDirection ( int curIdx , int motion )
    {
        std::cout << "\nNextFrom=" << curIdx << " motion =" << motion << "\n";
        curIdx +=motion;
        for (int i = curIdx; (i - curIdx) * motion < Count ; i += motion)
            std::cout << a[(i + Count) % Count] << " ";
    
        std::cout << "\n";
    }
    
    int main()
    {
        LoopFromMidWithDirection(4, +1);
        LoopFromMidWithDirection(6, +1);
        LoopFromMidWithDirection(0, -1);
    }
    

    输出

    NextFrom=4 motion =1
    5 0 1 2 3 4 
    
    NextFrom=6 motion =1
    1 2 3 4 5 0 
    
    NextFrom=0 motion =-1
    5 4 3 2 1 0 
    

    解决方案的灵感来自@Neil Kimber

    【讨论】:

      【解决方案4】:

      是的,您必须在自定义类上实现IEnumerator 接口。将逻辑写入 MoveNext 方法,检测数组的结尾,然后从数组的开头开始,记住中间的起点。

      以微软these code samples为模板。

      【讨论】:

        【解决方案5】:
        (DEFINE (traverse length start call) 
          (DEFINE (flow index motion)
            (cond ((> index length) 
                      (flow (- start 1) -1))
                  ((> index -1) 
                      ((call index) (flow (+ index motion) motion)))))
          (flow start +1))
        
        (traverse 9 5 job)
        

        我喜欢问题的 9 到 5 方面。我想知道他们是否在暗示什么?假设job 打印出数组索引,这将产生 678954321。

        在 C 中,我很想使用 for 循环(而不是我在编辑之前使用的 while 循环);

        int a[]= { 1,2,3,4,5,6,7,8,9,10};
        int length = 10;
        int start = 5;
        int motion = 1; //increment
        
        for( int index = start; index >= 0; index += motion ) {
          if(index > (length-1)) {
            motion = -1; //decrement
            index = start -1;
          else {
            printf("%d", a[index]);
          }
        }
        

        该过程仅在您打印零索引后完成。唯一不遍历数组的时间是超过它的时候。发生这种情况时,您将返回起始索引 (-1) 并反转运动。

        【讨论】:

          猜你喜欢
          • 2015-10-20
          • 2018-04-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-04-13
          • 2021-04-08
          • 2021-08-09
          • 2020-05-15
          相关资源
          最近更新 更多