Найти все возможные комбинации слов с дефисами и без дефисов
для строки, в которой может быть ноль или более дефисов, мне нужно извлечь все различные возможности с дефисами и без них.
например, строка "A-B" приведет к "A-B" и "AB" (две возможности).
строка "A-B-C" приведет к "A-B-C", "AB-C", "A-BC" и "ABC" (четыре возможности).
строка "A-B-C - D" приведет к "A-B-C-D", "AB-C-D", "A-BC-D", "A-B-CD", "AB-CD", "ABC-D", "A-BCD" и "ABCD" (восемь возможности.)
...и т. д. и т. п.
я экспериментировал с некоторыми вложенными циклами, но не смог приблизиться к желаемому результату. Я подозреваю, что мне нужно что-то рекурсивное, если нет простого решения, которое я упускаю.
NB. Это должно построить SQL-запрос (позор, что SQL Server не имеет соответствия шаблону регулярного выражения MySQL).
вот одна попытка, над которой я работал. Это может сработать, если я сделаю это. рекурсивно.
string keyword = "A-B-C-D";
List<int> hyphens = new List<int>();
int pos = keyword.IndexOf('-');
while (pos != -1)
{
hyphens.Add(pos);
pos = keyword.IndexOf('-', pos + 1);
}
for (int i = 0; i < hyphens.Count(); i++)
{
string result = keyword.Substring(0, hyphens[i]) + keyword.Substring(hyphens[i] + 1);
Response.Write("<p>" + result);
}
A B C D-слова различной длины.
5 ответов
вы должны иметь возможность отслеживать каждую позицию дефиса и в основном говорить ее либо там, либо нет. Пройдитесь по всем комбинациям, и вы получите все ваши строки. Я нашел самый простой способ отслеживать его с помощью двоичного файла, так как его легко добавить с Convert.ToInt32
Я придумал это:
string keyword = "A-B-C-D";
string[] keywordSplit = keyword.Split('-');
int combinations = Convert.ToInt32(Math.Pow(2.0, keywordSplit.Length - 1.0));
List<string> results = new List<string>();
for (int j = 0; j < combinations; j++)
{
string result = "";
string hyphenAdded = Convert.ToString(j, 2).PadLeft(keywordSplit.Length - 1, '0');
// Generate string
for (int i = 0; i < keywordSplit.Length; i++)
{
result += keywordSplit[i] +
((i < keywordSplit.Length - 1) && (hyphenAdded[i].Equals('1')) ? "-" : "");
}
results.Add(result);
}
взгляните на ваши примеры. Вы заметили закономерность?
- С 1 дефисом есть 2 возможности.
- С 2 дефисами есть 4 возможности.
- С 3 дефисами есть 8 возможностей.
количество возможностей равно 2n.
это буквально экспоненциальный рост, поэтому, если в строке слишком много дефисов, быстро станет невозможным распечатать их все. (С всего 30 дефисов - это более миллиарда комбинаций!)
тем не менее, для меньшего количества дефисов может быть интересно создать список. Для этого вы можете рассматривать каждый дефис как бит в двоичном числе. Если бит равен 1, дефис присутствует, в противном случае его нет. Таким образом, это предлагает довольно простое решение:
- разделить исходную строку на дефисы
- пусть n = число дефисов
- отсчет от 2n - 1 до 0. Рассматривайте этот счетчик как битовую маску.
- для каждого счета начните строить строку, начиная с первой части.
- объединить все оставшиеся детали в строку в порядке, предшествовать дефис, только если соответствующий бит в битовой маске находится.
- добавьте полученную строку к выходу и продолжайте, пока счетчик не будет исчерпан.
в переводе на код у нас есть:
public static IEnumerable<string> EnumerateHyphenatedStrings(string s)
{
string[] parts = s.Split('-');
int n = parts.Length - 1;
if (n > 30) throw new Exception("too many hyphens");
for (int m = (1 << n) - 1; m >= 0; m--)
{
StringBuilder sb = new StringBuilder(parts[0]);
for (int i = 1; i <= n; i++)
{
if ((m & (1 << (i - 1))) > 0) sb.Append('-');
sb.Append(parts[i]);
}
yield return sb.ToString();
}
}
Скрипка: https://dotnetfiddle.net/ne3N8f
это работает для меня:
Func<IEnumerable<string>, IEnumerable<string>> expand = null;
expand = xs =>
{
if (xs != null && xs.Any())
{
var head = xs.First();
if (xs.Skip(1).Any())
{
return expand(xs.Skip(1)).SelectMany(tail => new []
{
head + tail,
head + "-" + tail
});
}
else
{
return new [] { head };
}
}
else
{
return Enumerable.Empty<string>();
}
};
var keyword = "A-B-C-D";
var parts = keyword.Split('-');
var results = expand(parts);
Я:
ABCD A-BCD AB-CD A-B-CD ABC-D A-BC-D AB-C-D A-B-C-D
Я тестировал этот код и он работает, как указано в вопросе. Я сохранил строки в List<string>
.
string str = "AB-C-D-EF-G-HI";
string[] splitted = str.Split('-');
List<string> finalList = new List<string>();
string temp = "";
for (int i = 0; i < splitted.Length; i++)
{
temp += splitted[i];
}
finalList.Add(temp);
temp = "";
for (int diff = 0; diff < splitted.Length-1; diff++)
{
for (int start = 1, limit = start + diff; limit < splitted.Length; start++, limit++)
{
int i = 0;
while (i < start)
{
temp += splitted[i++];
}
while (i <= limit)
{
temp += "-";
temp += splitted[i++];
}
while (i < splitted.Length)
{
temp += splitted[i++];
}
finalList.Add(temp);
temp = "";
}
}
Я не уверен, что ваш вопрос полностью определен (т. е. Может ли у вас быть что-то вроде A-BCD-EF-G-H?). Для" полностью " дефисных строк (A-B-C-D -...- Z), что-то вроде этого должно сделать:
string toParse = "A-B-C-D";
char[] toParseChars = toPase.toCharArray();
string result = "";
string binary;
for(int i = 0; i < (int)Math.pow(2, toParse.Length/2); i++) { // Number of subsets of an n-elt set is 2^n
binary = Convert.ToString(i, 2);
while (binary.Length < toParse.Length/2) {
binary = "0" + binary;
}
char[] binChars = binary.ToCharArray();
for (int k = 0; k < binChars.Length; k++) {
result += toParseChars[k*2].ToString();
if (binChars[k] == '1') {
result += "-";
}
}
result += toParseChars[toParseChars.Length-1];
Console.WriteLine(result);
}
идея здесь заключается в том, что мы хотим создать двоичное слово для каждого возможного дефис. Итак, если у нас есть A-B-C-D (три дефиса), мы создаем двоичные слова 000, 001, 010, 011, 100, 101, 110, и 111. Обратите внимание, что если у нас есть N дефисов, нам нужно 2^n двоичных слов.
затем каждое слово карты к выходу, который вы хотите, вставив дефис, где у нас есть " 1 " в нашем слове (000 -> ABCD, 001 -> ABC-D, 010 -> AB-CD и т. д.). Я не тестировал код выше, но это, по крайней мере, один из способов решить проблему для полностью дефисных слов.
отказ от ответственности: я на самом деле не проверить код