1

Я хочу создать динамический генератор строк, который будет генерировать все возможные уникальные строки из набора символов с динамической длиной.Динамический генератор символов; Сгенерируйте все возможные строки из набора символов

Я могу сделать это очень легко, используя для циклов, но затем его статическую и не динамическую длину.

// Prints all possible strings with the length of 3 

for a in allowedCharacters { 
    for b in allowedCharacters { 
     for c in allowedCharacters { 
      println(a+b+c) 
     } 
    } 
} 

Но когда я хочу, чтобы сделать эту динамику длины, так что я могу просто позвонить generate(length: 5) я запутаться.

Я нашел это Stackoverflow question Но принятый ответ генерирует строки длиной 1-maxLength, и я хочу maxLength на любой строке.

+1

Почему бы не использовать рекурсию? – Dmitry

+2

@Arbitur не забудьте объяснить, что «сделало дубликаты и не было заказано» означает - нет никаких упоминаний о каких-либо ограничениях в вашем сообщении, и все же вы утверждаете, что связанное решение неприемлемо ... –

+0

@AlexeiLevenkov Связанный ответ породил что-то например: a, b, aa, aa, ab, bb, bb, ab. Несколько дубликатов. – Arbitur

ответ

4

Как указано выше, используйте рекурсию. Вот как это можно сделать с помощью C#:

static IEnumerable<string> Generate(int length, char[] allowed_chars) 
{ 
    if (length == 1) 
    { 
     foreach (char c in allowed_chars) 
      yield return c.ToString(); 
    } 
    else 
    { 
     var sub_strings = Generate(length - 1, allowed_chars); 

     foreach (char c in allowed_chars) 
     { 
      foreach (string sub in sub_strings) 
      { 
       yield return c + sub; 
      } 

     } 
    } 
} 

private static void Main(string[] args) 
{ 

    string chars = "abc"; 

    List<string> result = Generate(3, chars.ToCharArray()).ToList(); 

} 

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

+0

Я перевешу это на Swift and Ill return :) – Arbitur

+0

Этот взгляд в основном идентичен решению, предложенному в связанном сообщении. Пожалуйста, не забудьте уточнить, как это происходит (игнорируя часть итератора). Он также не учитывает тот факт, что связанное предложение «сделало дубликаты и не было заказано» (что бы это ни значило). –

+0

Указанный вопрос требует всех строк длины до определенной длины, однако для этого вопроса требуются все строки определенной длины. Ответ в другом вопросе заключается в записи результатов непосредственно на консоль, здесь мы генерируем данные и возвращаем их вызывающему. –

1

Перевода @ C# код YacoubMassad к Swift:

func generate(length: Int, allowedChars: [String]) -> [String] { 
    if length == 1 { 
     return allowedChars 
    } 
    else { 
     let subStrings = generate(length - 1, allowedChars: allowedChars) 

     var arr = [String]() 
     for c in allowedChars { 
      for sub in subStrings { 
       arr.append(c + sub) 
      } 
     } 

     return arr 
    } 
} 

println(generate(3, allowedChars: ["a", "b", "c"])) 

гравюр:

ааа, ааЪ, ААС, аба, АВВЫ, азбука, ас, ACB, акк, бея, бабы, BAC, BBA, ГЭБ, BBC, BCA, BCB, ОЦК, CAA, кабина, сас, CBA, CBB, CBC, CCA, CCB, ссс

+0

Если вас интересует обзор (например, возможные улучшения) вашего кода, вы можете опубликовать его на http://codereview.stackexchange.com/tour. –

+0

Спасибо @MartinR Я так и не исследовал другие форумы обмена стеками :) – Arbitur

1

в то время как вы можете (достаточно очевидно) использовать рекурсию, чтобы решить T его проблема, это довольно неэффективный способ выполнить эту работу.

Что вы действительно делаете, просто считаете. В вашем примере с «a», «b» и «c» в качестве допустимых символов вы считаете в базе 3, и поскольку вы разрешаете три символьные строки, они представляют собой трехзначные числа.

номер N-цифра в базовой M может представлять N M различных возможных значения, переходя от 0 до N М -1. Итак, для вашего дела, это limit=pow(3, 3)-1;. Чтобы сгенерировать все эти значения, вы просто считаете от 0 до предела и конвертируете каждое число в базу M, используя указанные символы в качестве «цифр». Например, в C++ код может выглядеть следующим образом:

#include <string> 
#include <iostream> 

int main() { 
    std::string letters = "abc"; 
    std::size_t base = letters.length(); 
    std::size_t digits = 3; 

    int limit = pow(base, digits); 

    for (int i = 0; i < limit; i++) { 
     int in = i; 
     for (int j = 0; j < digits; j++) { 
      std::cout << letters[in%base]; 
      in /= base; 
     } 
     std::cout << "\t"; 
    } 
} 

Одно незначительное замечание: как я написал здесь, это производит вывод в основном используется прямой порядок байтов. То есть, «цифра», которая отличается самым быстрым, находится слева, а одна, которая меняет самый медленный, находится справа.