2013-06-26 4 views
-2

Я хочу написать метод, который возвращает строку. Все идет нормально. Однако создание строки довольно сложно. У меня есть 3 строковых списка: первый имеет 155 записей, второй - 9, третий - 21. Я хочу, чтобы мой метод вызывал достаточно времени (155 * 9 * 21), чтобы вернуть все возможные комбинации значений из 3 (в основном этот метод должен учитывать количество раз, когда он был вызван, и возвращать только одну комбинацию каждый раз). Любые идеи, как это сделать?Ошибка строкового генератора

У меня есть 155 * 9 * 22 возможных комбинаций. При первом вызове метода он должен принимать List1 (0), List2 (0), List3 (0). После этого в следующих 21 итерации индекс третьего списка изменяется только. После того, как все элементы из третьего списка были использованы, увеличьте индекс второго списка и так далее.

Как только метод создал все возможные комбинации (155 * 9 * 22), я хочу, чтобы он начинался с самого начала.

+0

Возможно, вам стоит попробовать 'yield return': [example] (http://msdn.microsoft.com/en-us/library/vstudio/9k7k7cf0.aspx) –

+0

так же просто, как три для циклов; для каждого слова в каждом цикле распечатывают результаты –

ответ

1

Использовал старый добрый оператор modulo. Возможно, можно оптимизировать намного больше.

public class Generator 
{ 
    private int index = 0; 
    private List<string> list1 = new List<string> { "a", "b" }; 
    private List<string> list2 = new List<string> { "c", "d" }; 
    private List<string> list3 = new List<string> { "e", "f", "g" }; 

    public string Next() 
    { 
     int indexList3 = index % list3.Count; 
     int indexList2 = (index/list3.Count) % list2.Count; 
     int indexList1 = (index/(list2.Count * list3.Count)) % list1.Count; 

     IncrementIndex(); 

     return list1[indexList1] + list2[indexList2] + list3[indexList3]; 
    } 

    private void IncrementIndex() 
    { 
     index++; 
     if (index > list1.Count*list2.Count*list3.Count) 
     { 
      index = 0; 
     } 
    } 
} 

поэтому первые 13 результатов (на 12 возможных комбинаций), полученные с

string result = string.Empty; 
Generator generator = new Generator(); 

for (int i = 0; i < 13; i++) 
{ 
    result += generator.Next() + "\n"; 
} 

выходов:

ace 
acf 
acg 
ade 
adf 
adg 
bce 
bcf 
bcg 
bde 
bdf 
bdg 
ace 
3

Вы можете просто перечислить все возможные комбинации, например:

public IEnumerable<String> generator() { 
     foreach (String item1 in List1) 
     foreach (String item2 in List2) 
      foreach (String item3 in List3) 
      yield return item1 + item2 + item3; 
    } 

    ... 

    foreach (String item in generator()) { 
    // Do something with generated strings 
    } 
+0

да, но генерация строки должна происходить только при вызове метода, и я стараюсь сохранить, насколько далеко я получил тот же метод, используя некоторые индексы. – Andrey

+0

@ Andrey прочитал ссылку, которую я разместил в комментариях к вашему вопросу –

+0

да, это вернет все возможные комбинации. Однако я хочу, чтобы мой метод выполнял вычисления только тогда, когда он был вызван, и чтобы он учитывал, насколько он прошел.Возможный способ - получить все комбинации и просто проиндексировать их, но если я решит расширить метод (добавить еще один список), то это приведет к множеству результатов, которые являются нежелательным использованием памяти. – Andrey

1

Вы можете оставить индекс для каждого списка:

public IEnumerable<string> Permutations(string[][] lists, int start = 0) { 
    int[] position = new int[lists.Length]; 

    for(int i = lists.Length - 1; start > 0; i--) { 
     position[i] = start % lists[i].Length; 
     start /= lists[i].Length; 
    } 

    while(true) { 
     int i; 
     string current = string.Empty; 

     for(i = lists.Length - 1; i >= 0; i--) { 
      if(++position[i] == lists[i].Length) { 
       position[i] = 0; 
       current = lists[i][0] + current; 
      } else { 
       break; 
      } 
     } 

     if(i == -1) break; 

     while(i > -1) { 
      current = lists[i][position[i]] + current; 
      i--; 
     } 

     yield return current; 
    } 
} 

Это занимает место, чтобы начать, возможно, так вы можете сохранить только одно целое и создать следующий элемент.

Я не тестировал это. Имейте в виду! :)

1
public IEnumerable<string> List1 = new [] { "A", "B", "C" }; 
public IEnumerable<string> List2 = new [] { "1", "2", "3" }; 
public IEnumerable<string> List3 = new [] { "Z", "Y" }; 

public IEnumerator<string> StringEnumerator; 

public void InitializeEnumerator() 
{ 
    var stringEnumerable = List1.SelectMany(x => List2.SelectMany(y => List3.Select(z => x + y + z))); 

    StringEnumerator = stringEnumerable.GetEnumerator(); 
} 

public string GetNextString() 
{ 
    return StringEnumerator.MoveNext() ? StringEnumerator.Current : null; 
} 

Просто позвоните InitializeEnumerator(), то вы получите новую строку из каждого вызова GetNextString()

InitializeEnumerator(); 
GetNextString(); //-> A1Z 
GetNextString(); //-> A1Y 
GetNextString(); //-> A2Z 
GetNextString(); //-> A2Y 
GetNextString(); //-> A3Z 
GetNextString(); //-> A3Y 
GetNextString(); //-> B1Z 

Чтобы его автоматической инициализации и повторной инициализации после того, как она закончится , измените GetNextString следующим образом.

public string GetNextString() 
{ 
    if(StringEnumerator == null || !StringEnumerator.MoveNext()) 
    { 
     InitializeEnumerator(); 
     StringEnumerator.MoveNext(); 
    } 

    return StringEnumerator.Current; 
} 
+0

И как только он покрыл все комбинации, как заставить его снова начать повторение с первого? – Andrey

+0

Просто вызовите InitializeEnumerator() еще раз. –

+0

Я изменил свой ответ, включив в него цикл-версию GetNextString –

1

с использованием способа, показанного на Dmitry Bychenko, вы можете отслеживать, как далеко вы находитесь в списках:

// use his generator method 
public IEnumerable<String> generator() 
{ 
    ... 
} 

.... 

int counter = 0; 
foreach (String item in generator()) 
{ 
    // compute indexes 
    int ix_list3 = counter % List3.Count; 
    int ix_list2 = (counter/List3.Count) % List2.Count; 
    int ix_list1 = (counter/(List3.Count * List2.Count)); 

    // do something with item and indexes 
    ++counter; 
}