Как проверить, состоит ли строка из определенных символов?
Пользователь вводит число неизвестной длины, например 6744.
Есть набор чисел (0..9999)
Из этого набора нужно исключить комбинации, состоящие из цифр введенного числа. ( Т.е. 6, 4, 7, .... 4674, 7446, 4467 и др.)
Как это лучше сделать? Contains как по мне не канон в этом случае! Может регулярки там или linq?
Ответы (3 шт):
Можно как то так попробовать:
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];
}
);
}
}
}
}
}
Перебор 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);
}
}
}
Код не тестил, но все должно пахать.
Все просто максимально деревяно.
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 ) окажется быстрее. Но практически наверняка там есть ошибки которые прийдется долго искать и дебажить) При "деревяном" же подходе ошибиться сложно, а ошибки исправлять очень просто, даже, если они есть.