我需要正模数用于数组索引迭代

时间:2012-01-31 16:31:40

标签: c# indexing modulo

我有一个由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"}
    等等...
  4. 我已通过以下方法实现了所需的功能:

    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开始返回负值,这使得模数也开始返回负值。整个功能失败了。我需要使模数始终返回正值,就像在Microsofot Excel(mod函数)中一样。

    你能帮我修一下int order的公式吗?谢谢。

7 个答案:

答案 0 :(得分:3)

这是完成这项工作的一种错综复杂的方式,它实际上根本不起作用,不仅仅是当iterationNum太大时。这应该有所帮助:

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,则函数返回原始列表。

答案 1 :(得分:1)

尝试

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

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

答案 2 :(得分:1)

你的解决方案是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));

答案 3 :(得分:1)

我在这里实现了这个目标: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

答案 4 :(得分:1)

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;
    }
}

答案 5 :(得分:1)

好的,第二次尝试:

    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 :(得分:0)

这是一些我用更好的运行时间编写的代码。它适用于包含的单元测试,如果我没有在第一次完全确定它,你可以从那里进行调整...

[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]);
    }
}