Как написать генератор анаграмм в чистых системах С# и .Net

Я хотел бы генерировать вывод анаграммы данной строки без помощи каких-либо внешних библиотек, таких как помощник алгоритмов алгоритмов Google.

Пример:

Входная строка = "БОГ"

Список вывода должен выглядеть следующим образом:

G O D GO GD OD OG DG DO GOD GDO ODG OGD DGO DOG

Ответ 1

То, что taks оказалось потрясающим на стольких уровнях. Я представляю вам чистое LINQ (но не очень эффективное) решение.

    static class Program
    {
        static void Main(string[] args)
        {
            var res = "cat".Anagrams();

            foreach (var anagram in res)
                Console.WriteLine(anagram.MergeToStr());
        }

        static IEnumerable<IEnumerable<T>> Anagrams<T>(this IEnumerable<T> collection) where T: IComparable<T>
        {
            var total = collection.Count();

            // provided str "cat" get all subsets c, a, ca, at, etc (really nonefficient)
            var subsets = collection.Permutations()
                .SelectMany(c => Enumerable.Range(1, total).Select(i => c.Take(i)))
                .Distinct(new CollectionComparer<T>());

            return subsets;
        }

        public static IEnumerable<IEnumerable<T>> Permutations<T>(this IEnumerable<T> collection)
        {
            return collection.Count() > 1 
                ?
                    from ch in collection
                    let set = new[] { ch }
                    from permutation in collection.Except(set).Permutations()
                    select set.Union(permutation)
                :
                    new[] { collection };
        }

        public static string MergeToStr(this IEnumerable<char> chars)
        {
            return new string(chars.ToArray());
        }

    }// class

    // cause Distinct implementation is shit
    public class CollectionComparer<T> : IEqualityComparer<IEnumerable<T>> where T: IComparable<T>
    {
        Dictionary<IEnumerable<T>, int> dict = new Dictionary<IEnumerable<T>, int>();

        public bool Equals(IEnumerable<T> x, IEnumerable<T> y)
        {
            if (x.Count() != y.Count())
                return false;
            return x.Zip(y, (xi, yi) => xi.Equals(yi)).All(compareResult => compareResult);
        }

        public int GetHashCode(IEnumerable<T> obj)
        {
            var inDict = dict.Keys.FirstOrDefault(k => Equals(k, obj));
            if (inDict != null)
                return dict[inDict];
            else
            {
                int n = dict.Count;
                dict[obj] = n;
                return n;
            }
        }
    }// class

Ответ 3

Для чего это стоит, я написал методы на Java, которые будут делать то, что вы хотите, и я понимаю, что С# достаточно похож, вы, вероятно, сможете прочитать код без особых проблем. (Синтаксис, т.е. Если вам неудобно рекурсивные функции, это может вызвать проблемы.) Мое имя пользователя @ undefined на этом форуме нить. Чтобы использовать код, вы можете перебирать значения k от 1 до длины строки включительно. Кроме того, вы можете сгенерировать все подмножества (отбрасывая пустой набор), как описано в этот поток, а затем получить перестановки оттуда. Другой способ - написать функцию kth-перестановки и использовать ее. У меня нет ни одного опубликованного онлайн; тот, который я использую, немного беспорядочен, и я должен переписать его когда-нибудь.

Изменить: Стоит отметить, что я написал методы таким образом, который казался простым, но более эффективным было бы использование стека, так что вам не нужно создавать множество новых объектов.

Ответ 4

попробуйте это

public static IEnumerable<string> Permutations(this string text)
{
    return PermutationsImpl(string.Empty, text);
}

private static IEnumerable<string> PermutationsImpl(string start, string text)
{
    if (text.Length <= 1)
        yield return start + text;
    else
    {
        for (int i = 0; i < text.Length; i++)
        {
            text = text[i] +
                    text.Substring(0, i) +
                    text.Substring(i + 1);
            foreach (var s in PermutationsImpl(start +
                text[0], text.Substring(1)))
                yield return s;
        }
    }
}

то просто используйте этот метод расширения таким образом

string text = "CAT";
List<string> perms = text.Permutations().ToList();