Как проверить, состоит ли строка из определенных символов?

  1. Пользователь вводит число неизвестной длины, например 6744.

  2. Есть набор чисел (0..9999)

  3. Из этого набора нужно исключить комбинации, состоящие из цифр введенного числа. ( Т.е. 6, 4, 7, .... 4674, 7446, 4467 и др.)

Как это лучше сделать? Contains как по мне не канон в этом случае! Может регулярки там или linq?


Ответы (3 шт):

Автор решения: Yaroslav

Можно как то так попробовать:

public class Program
{
    public static void Main(string[] args)
    {
        var nums = new int[] { 6, 7, 4, 4 };
        List<int> result = new List<int>();
        foreach (var permutation in Permutations<int>.AllFor(nums))
        {
            var f = Convert.ToInt32(string.Join("", permutation));
            result.Add(f);
        }
        
        var withMissed = result.Where(x => x != 4674 && x != 7446 && x != 4467).ToList();
        
        result.Distinct().ToList().ForEach(x => Console.WriteLine(x));
        Console.WriteLine("----------");
        withMissed.Distinct().ToList().ForEach(x => Console.WriteLine(x));
    }
}

public class Permutations<T>
{
    public static IEnumerable<T[]> AllFor(T[] array)
    {
        if (array == null || array.Length == 0)
        {
            yield return new T[0];
        }
        else
        {
            for (int pick = 0; pick < array.Length; ++pick)
            {
                T item = array[pick];
                int i = -1;
                T[] rest = Array.FindAll<T>(
                    array, delegate(T p) { return ++i != pick; }
                );
                foreach (T[] restPermuted in AllFor(rest))
                {
                    i = -1;
                    yield return Array.ConvertAll<T, T>(
                        array,
                        delegate(T p)
                        {
                            return ++i == 0 ? item : restPermuted[i - 1];
                        }
                    );
                }
            }
        }
    }
}
→ Ссылка
Автор решения: Yaroslav

Перебор 0-9999 ломается об колено пунктом неизвестной длины. Пятизначное число уже не сработает. По мимо того, что он невероятно грузный.

Нужно использовать рекурсию.

Ввели 123. Всего шесть вариантов:

          ...
    /      |      \
  1..     2..     3..
  / \     / \     / \
12. 13. 21. 23. 32. 31.
 |   |   |   |   |   |
123 132 213 231 321 312
      

Конструируем строки перебором индексов, удаляя использованные. А затем проверив, есть ли в InputNumber одинаковые цифры, использовать Distinct, поскольку если совпадений нет, это операция лишняя и грузная с большими цифрами.

string InputNumber;
// если число из одной цифры всё совсем просто
if (InputNumber.Length == 1)
    return new[] { int.Parse(InputNumber) };

List<int> numbers = new List<int>();
Generator(numbers, InputNumber);

// Проверка на одинаковые символы
List<char> CharsOfNumbers = new List<char>(InputNumber.ToCharArray());
CharsOfNumbers.Distinct();

if (CharsOfNumbers.Count != InputNumber.Length)
    numbers.Distinct();

return numbers.ToArray();

Рекурсивный метод:

private void Generator (List<int> resultNumbers, string number, string result = "") {
    if (number.Length < 2)
        resultNumbers.Add(int.Parse(result+number));
    else {
        for (int i = 0; i < number.Length; i++) {
            string NewResult = result+number[i].ToString(); // Генерируемое число
            string NewNumber = number.Remove(i, 1); // Неиспользованные числа
            Generator(resultNumbers, NewNumber, NewResult);
        }
    }
}
→ Ссылка
Автор решения: Andrew

Код не тестил, но все должно пахать.

Все просто максимально деревяно.

Int number = 6744;

var symbols = number.ToString()
                    .ToCharArray()
                    .Distinct();

var exceptions = Enumerable
                    .Range     (1, 4) // макс число 9999 - значит числа не более 4 символов
                    .Select    ( a => symbols.DifferentCombinations(a) )
                    .SelectMany( b => Int32.Parse(new string(b)) );

var result = Enumerable
                    .Range(0, 9999)
                    .Except(exceptions);

extension:

public static class Ex
{
    public static IEnumerable<IEnumerable<T>> DifferentCombinations<T>(this IEnumerable<T> elements, int k)
    {
        return k == 0 ? new[] { new T[0] } :
          elements.SelectMany((e, i) =>
            elements.Skip(i + 1).DifferentCombinations(k - 1).Select(c => (new[] {e}).Concat(c)));
    }
}

Экстеншн скомуниздил отсюда: https://stackoverflow.com/a/33336576/4423545

Код писал из головы без вижуалки, поэтому могут быть синтаксические ошибки. Исправишь сам.


Можно ли сделать код быстрее? Можно. Но код будет запутанным и с большей вероятностью с ошибками. Лично я предпочитаю писать более простой и понятный код, чем оптимальный по скорости. А скорость оптимизировать уже по мере необходимости.

Наверняка код Yaroslav (через yield ) окажется быстрее. Но практически наверняка там есть ошибки которые прийдется долго искать и дебажить) При "деревяном" же подходе ошибиться сложно, а ошибки исправлять очень просто, даже, если они есть.

→ Ссылка