Сочетание двух символов

Я ввожу ввод как int, и в соответствии с этим вводом мне нужна комбинация двух символов, НАПРИМЕР я ввожу ввод как 2, и у меня есть два символа x и y, поэтому я хочу такие комбинации, как

    xx,yy,xy,yx

Если вход равен 3, я хочу

    xxx,xyy,xxy,xyx,yxx,yyy,yxy.yyx

и так далее, я попробовал следующий код,

     int input1 = 4;
        Double totalpossibilities = Math.Pow(2, input1);
        string[] PArray = new string[Convert.ToInt16(totalpossibilities)];
        char[] chars = new char[] { 'x', 'y'};

        for (int i = 0; i < totalpossibilities; i++)
        {
            string possibility = "" ;
            for (int j = 0; j < input1; j++)
            {
                Random random = new Random();
                int r = random.Next(chars.Length);
                char randomChar = chars[r];
                possibility = possibility + randomChar;

            }
            if (PArray.Contains(possibility))
            {
                i--;
            }
            else
                PArray[i] = possibility;
        }

Но, как вы можете видеть, я использую случайную функцию, поэтому я слишком долго выполняю ее. Есть ли какая-то другая логика?


person Hiren    schedule 15.05.2012    source источник
comment
Попробуйте извлечь инициализацию random в начало вашей программы... или вам нужно новое семя на каждой итерации?   -  person Nick Babcock    schedule 15.05.2012
comment
Он вообще не должен использовать random для решения этой проблемы.   -  person Magnus    schedule 15.05.2012
comment
@Magnus Я знаю, что не должен использовать случайный выбор, но есть ли способ получить перестановки? Можете ли вы помочь в этом?   -  person Hiren    schedule 15.05.2012
comment
@ Hiren, у Серви есть для тебя хороший ответ.   -  person Magnus    schedule 15.05.2012


Ответы (5)


Вы можете запустить цикл for от 0 до totalpossibilities. Преобразуйте i в двоичный формат, например, на 20-й итерации это даст «10100». Дополнить результат до input1 символов, например (для 8 знаков): 00010100 Затем преобразовать в строку и заменить все нули на «x», все единицы на «y».

        int places = 4;
        Double totalpossibilities = Math.Pow(2, places);

        for (int i = 0; i < totalpossibilities; i++)
        {
            string CurrentNumberBinary = Convert.ToString(i, 2).PadLeft(places, '0');

            CurrentNumberBinary = CurrentNumberBinary.Replace('0', 'x');
            CurrentNumberBinary = CurrentNumberBinary.Replace('1', 'y');
            Debug.WriteLine(CurrentNumberBinary);
        }
person svenv    schedule 15.05.2012
comment
Я понимаю, но я не хочу использовать случайную функцию, потому что предположим, что ввод равен 200, это займет очень много времени. - person Hiren; 15.05.2012
comment
Количество возможных строк равно 2^n. Максимальный ввод, который вы можете решить за всю жизнь, вероятно, меньше 32. - person Samy Arous; 15.05.2012
comment
Интересное решение. Но так как Convert.ToString(Int32, Int32) не работает с троичными, четверичными и т. д., он не работает с тремя, четырьмя и т. д. буквами. Я написал другое решение. - person Jeppe Stig Nielsen; 15.05.2012

Использование копии метода расширения Cartesian Product, дословно скопированного из здесь:

static IEnumerable<IEnumerable<T>> CartesianProduct<T>(this IEnumerable<IEnumerable<T>> sequences) 
{ 
  IEnumerable<IEnumerable<T>> emptyProduct = new[] { Enumerable.Empty<T>() }; 
  return sequences.Aggregate( 
    emptyProduct, 
    (accumulator, sequence) => 
      from accseq in accumulator 
      from item in sequence 
      select accseq.Concat(new[] {item})); 
}

Тогда в вашем коде вы можете иметь:

IEnumerable<char> possibleCharacters = "xy";//change to whatever
int numberOfDigits = 3;

var result = Enumerable.Repeat(possibleCharacters, numberOfDigits)
     .CartesianProduct()
     .Select(chars => new string(chars.ToArray()));

//display (or do whatever with) the results
foreach (var item in result)
{
    Console.WriteLine(item);
}
person Servy    schedule 15.05.2012
comment
В конце добавлен Select, чтобы у вас было перечисление строк, с которыми вам было бы легче иметь дело. Вы можете удалить этот выбор в конце, если вы предпочитаете перечисление перечисления символов. - person Servy; 15.05.2012
comment
Нужно ли вносить какие-либо изменения в этот код? Я использую тот же код, но получаю ошибку в var result = Enumerable.Repeat(possibleCharacters, numberOfDigits) .CartesianProduct() .Select(chars =› new string(chars.ToArray())); Не содержит определения «Декартово произведение». - person Hiren; 15.05.2012
comment
Метод декартова произведения должен быть в статическом классе, так как это метод расширения. Вы также можете реорганизовать его, чтобы он был обычным статическим методом, если хотите. - person Servy; 15.05.2012
comment
Я принимаю ответ svenv, но также поддерживаю ваш ответ, спасибо за помощь - person Hiren; 15.05.2012

если у вас всегда есть 2 символа, то самый простой способ - использовать комбинаторную природу целых чисел. если вы возьмете двоичную форму всех чисел от 2 ^ n до 2 ^ (n + 1) - 1, вы заметите, что она представляет все возможные комбинации «0» и «1» длины n :).

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

person Samy Arous    schedule 15.05.2012

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

public class Permutations
{
    public static string[][] GenerateAllPermutations(string[] tokens, int depth)
    {
        string[][] permutations = new string[depth][];

        permutations[0] = tokens;

        for (int i = 1; i < depth; i++)
        {
            string[] parent = permutations[i - 1];
            string[] current = new string[parent.Length * tokens.Length];

            for (int parentNdx = 0; parentNdx < parent.Length; parentNdx++)
                for (int tokenNdx = 0; tokenNdx < tokens.Length; tokenNdx++)
                    current[parentNdx * tokens.Length + tokenNdx] = parent[parentNdx] + tokens[tokenNdx];

            permutations[i] = current;
        }

        return permutations;
    }

    public static void Test()
    {
        string[] tokens = new string[] { "x", "y", "z" };
        int depth = 4;

        string[][] permutations = GenerateAllPermutations(tokens, depth);

        for (int i = 0; i < depth; i++)
        {
            foreach (string s in permutations[i])
                Console.WriteLine(s);

            Console.WriteLine(string.Format("Total permutations:  {0}", permutations[i].Length));
            Console.ReadKey();
        }
    }
}

Ваше здоровье,

person ThisGuy    schedule 15.05.2012

Вот решение с List<>. Обобщает на любое количество букв.

static List<string> letters = new List<string> { "x", "y", };

static List<string> MakeList(int input)
{
  if (input < 0)
    throw new ArgumentOutOfRangeException();

  var li = new List<string> { "", };

  for (int i = 0; i < input; ++i)
    li = Multiply(li);

  return li;
}

static List<string> Multiply(List<string> origList)
{
  var resultList = new List<string>(origList.Count * letters.Count);
  foreach (var letter in letters)
    resultList.AddRange(origList.Select(s => letter + s));
  return resultList;
}
person Jeppe Stig Nielsen    schedule 15.05.2012