Мне нужен положительный модуль для итерации индекса массива - PullRequest
1 голос
/ 31 января 2012

У меня есть список 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 (функция мода).

Не могли бы вы помочь мне исправить формулу для int order? Благодарю.

Ответы [ 7 ]

3 голосов
/ 31 января 2012

Это чертовски запутанный способ выполнения работы, и он на самом деле не работает вообще, не только когда 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 голос
/ 31 января 2012

Хорошо, вторая попытка:

    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;
    }
1 голос
/ 31 января 2012
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;
    }
}
1 голос
/ 31 января 2012

Я добился этого здесь: 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
1 голос
/ 31 января 2012

Ваше решение - 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));
1 голос
/ 31 января 2012

Попробуйте

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

для быстрого исправления.Хотя я бы попытался переписать метод, этот двойной цикл не нужен.

0 голосов
/ 31 января 2012

Вот некоторый код, который я добавил вместе с лучшим временем выполнения.Это работает для включенных модульных тестов, и вы можете откорректировать их, если я не прибил его точно в первый раз через ...

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