【问题标题】:I need positive modulus for array index iteration我需要数组索引迭代的正模数
【发布时间】:2012-01-31 16:31:39
【问题描述】:

我有一个列表 List A 由字符串 {"a", "b", "c", "d", "e"} 组成。 我的程序在迭代中运行,并且对于每次迭代,我想创建一个新列表List B,它将包含相同的字符串,但它们中的每一个都应该移动到左侧的一个位置。以下是List B 在前三个迭代中应该是什么样子的示例:

  1. 迭代,列表B应该是:listB = {"a", "b", "c", "d", "e"}
  2. 迭代,列表B应该是:listB = {"b", "c", "d", "e", "a"}
  3. 迭代,列表B应该是:listB = {"c", "d", "e", "a", "b"}
    等等……

我已经通过以下方法实现了所需的功能:

private List<string> CalculateQueueOrder(List<string> listA, int iterationNum)
{
    int listACount = listA.Count;
    List<string> listB = new List<string>();

    for (int i = 0; i < listACount; i++)
    {
        for (int j = 0; j < listACount; j++)
        {
            int order = ((j - iterationNum) % listACount + 1);
            if (order == i)
            {
                string listItem = listA[j];
                listB.Add(listItem);
                break;
            }
        }
    }
    return listB;
}

但是,这种方法存在问题。随着迭代次数的增加,j - iterationNum 开始返回负值,这使得模数也开始返回负值。整个功能失败。我需要让模数始终返回正值,就像在 Microsoft Excel(mod 函数)中所做的那样。

您能帮我解决int order 的公式吗?谢谢。

【问题讨论】:

  • 您是否致力于这种双循环范式?我认为您可以根据列表大小和迭代次数在 O(1) 时间内计算出您需要移动多少,然后简单地构建一个新列表。
  • @ErikDietrich 任何解决方案都可以。我不介意放弃 2 循环的想法。你能帮帮我吗?

标签: c# indexing modulo


【解决方案1】:

这是完成这项工作的一种非常复杂的方式,而且它实际上根本不起作用,不仅当迭代Num 太大时。这应该会有所帮助:

int order = ((listACount + j - iterationNum % listACount + 1) % listACount);

还有一个更简单的方法,以防万一:

private List<string> CalculateQueueOrder(List<string> list, int iterationNum) {
    iterationNum = (iterationNum - 1) % list.Count;
    return list.Skip(iterationNum).Concat(list.Take(iterationNum)).ToList();
}

这两种方法都假设迭代从 1 开始,而不是 0,即如果 iterationNum 等于 1,则函数返回原始列表。

【讨论】:

  • 如果列表中有 5 个项目,则 int order 计算在第 5 次迭代后失败。至于第二种解决方案,您能解释一下SkipTake 方法的含义吗?谢谢。
  • 好的,现在它应该适用于所有数字,即使是负数。 :>
  • 至于skip and take,这些是LINQ的一部分。这两个方法返回调用它们的集合的修改版本。 'Skip' 只是跳过前 n 个元素,并返回其余元素。 'Take' 获取前 n 个元素,并丢弃剩余的元素。 Concat 只是将一个集合附加到另一个集合。所以这三个方法只取集合的前 n 个元素并将它们附加到末尾,这正是您需要做的。 LINQ 是一个相对广泛的话题,也是让 c# 成为一门非常好的语言(与 java 相比)的原因之一,所以我强烈建议你阅读更多关于它的内容。
【解决方案2】:

我在这里实现了这一点:http://rextester.com/HXACA68585

方法是:

    private static IEnumerable<T> Cycle<T>(List<T> data, int num)
    {
        var start = num%data.Count;
        for(var i=0;i<data.Count;i++)
        {
            yield return data[(i+start)%data.Count];
        }
    }

如果您愿意,您可以将其填回到新列表中:

List<string> list = new List<string>(){"a", "b", "c", "d", "e"};
List<string> newList = new List<string>(Cycle(list,2)); // contains c, d, e, a, b

但要测试您所需的结果,请使用:

List<string> list = new List<string>(){"a", "b", "c", "d", "e"};
Dump(Cycle(list,0));
Dump(Cycle(list,1));
Dump(Cycle(list,2));
Dump(Cycle(list,3));
Dump(Cycle(list,4));
Dump(Cycle(list,5));
Dump(Cycle(list,6));

输出如下:

a, b, c, d, e
b, c, d, e, a
c, d, e, a, b
d, e, a, b, c
e, a, b, c, d
a, b, c, d, e
b, c, d, e, a

【讨论】:

    【解决方案3】:

    试试

    int order = ((j - iterationNum) % listACount + 1);
    if (order < 0) order += listACount + 1;
    

    快速修复。虽然我会尝试重写该方法,但应该不需要双循环。

    【讨论】:

    • 如果listA 中有 5 个列表项,就像上面的问题一样,在第二次迭代中添加行失败:字符串"a" 不会移动到listB 中的最后一个位置.
    【解决方案4】:

    您的解决方案是 O(N^2),而它可以在 O(N) 时间内解决:

    int iterationNumber = 2 % listA.Count; // substitute 2 with whatever number you want
    List<string> listA = new List<string> { "a", "b", "c", "d", "e", "f" };
    
    var listB = listA.Skip(iterationNumber).Concat(listA.Take(iterationNumber));
    

    【讨论】:

      【解决方案5】:

      好的,第二次尝试:

          public List<string> CalculateQueueOrder(List<string> list, int shift) {
              int len = list.Count;
              int start = shift % len;
      
              List<string> newList = new List<string>();
              for (int i = start; i < len; ++i) {
                  newList.Add(list[i]);
              }
              for (int i = 0; i < start; ++i) {
                  newList.Add(list[i]);
              }
      
              return newList;
          }
      

      【讨论】:

        【解决方案6】:
        var orglist = new List<string>() { "a", "b", "c", "d", "e" };
        
        foreach (var list in CalculateQueueOrder(orglist))    
        {
              Console.WriteLine(String.Join(" ",list));
        }
        
        IEnumerable<List<string>> CalculateQueueOrder(List<string> list)
        {
            //yield return list; //if you need the original list
            for (int i = 0; i < list.Count-1; i++)
            {
                var newList = new List<string>(list.Skip(1));
                newList.Add(list.First());
                list  = newList;
                yield return newList;
            }
        }
        

        【讨论】:

          【解决方案7】:

          以下是我将一些代码与更好的运行时结合在一起。它适用于包含的单元测试,如果我第一次没有准确地完成它,您可以从那里进行调整...

          [TestClass]
          public class ScratchPadTest
          {
          
              private int CalculateShift(int listCount, int iterations)
              {
                  if (listCount == 0)
                  { 
                      return 0;
                  }
                  return iterations % listCount;
              }
          
          
          
              private List<string> PerformShift(List<string> list, int iterations)
              {
                  var myShiftCount = CalculateShift(list.Count, iterations);
                  var myList = new List<string>();
          
                  for (int index = 0; index < myShiftCount; index++)
                  {
                      myList.Add(list[(index + myShiftCount) % list.Count]);
                  }
                  return myList;
              }
          
              [TestMethod, Owner("ebd"), TestCategory("Proven"), TestCategory("Unit")]
              public void ZeroIterationsReturns0()
              {
                  Assert.AreEqual<int>(0, CalculateShift(0, 0));
          
              }
          
              [TestMethod, Owner("ebd"), TestCategory("Proven"), TestCategory("Unit")]
              public void OneITerationReturnsOne_With_List_Size_Two()
              {
                  Assert.AreEqual<int>(1, CalculateShift(2, 1));
              }
          
              [TestMethod, Owner("ebd"), TestCategory("Proven"), TestCategory("Unit")]
              public void OneIterationReturns_Zero_With_ListSizeOne()
              {
                  Assert.AreEqual<int>(0, CalculateShift(1, 1));            
              }
          
              [TestMethod, Owner("ebd"), TestCategory("Proven"), TestCategory("Unit")]
              public void Shifting_Two_Element_List_By_101_Reverses_Elements()
              {
                  var myList = new List<string>() { "1", "2" };
          
                  Assert.AreEqual<string>("2", PerformShift(myList, 101)[0]);
              }
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-12-16
            • 1970-01-01
            • 1970-01-01
            • 2013-06-14
            相关资源
            最近更新 更多