0

How would one go about scrambling a string such as the following, so that every possible permutation is achieved? Is there a LINQ method for such an effort? I have searched Google, but could not find anything on it.

STRING = "Little Red Riding Hood"
Jeagr
  • 1,038
  • 6
  • 16
  • 30

4 Answers4

2

This is an excellent permutation library I have used in the past. The article has a code snippet included that I believe would match your needs well (which I've slightly adapted):

var inputSet = myString.ToCharArray();
var P2 = new Permutations<char>(inputSet, 
      GenerateOption.WithRepetition);
string format2 = "Permutations of {{A A C}} with Repetition; size = {0}";
Console.WriteLine(String.Format(format2, P2.Count));
foreach(IList<char> p in P2) {
  Console.WriteLine(String.Format("{{{0} {1} {2}}}", p[0], p[1], p[2]));
}
Nathan Anderson
  • 6,768
  • 26
  • 29
  • Nathan, does this work with words instead of characters? I have something similar that I was working with, but I was having trouble converting it from a char algo to a word algo. – Jeagr Mar 03 '13 at 00:25
  • 1
    It is a generic library, so you can generate Permutations of anything that implements `IComparable`. When I originally found the project I discovered it did not support types who only implement `IComparable` - I posted a comment that includes a code fix to address this. I am not sure if the author incorporated this into the library. (Comment is on this page http://www.codeproject.com/Articles/26050/Permutations-Combinations-and-Variations-using-C-G?fid=1313343&df=90&mpp=10&noise=1&prof=True&sort=Position&view=Expanded&spc=None&fr=61#xx0xx) – Nathan Anderson Mar 03 '13 at 00:44
1

There are methods in the C++ Standard Template Library (STL), but I believe those are not accessible (in any maningful way) from C#. I believe you would have to write a little C++ wrapper for the STL and invoke that from C#; or code the permutations in C#.

Update:

Generating all permutations of N items is a necessary prelude to the Traveling Salesman Problem (TSP). Algorithms for this are all over the web, which will explain generating the permutaions in various possible sequential and parallel algorithms en passant.

Pieter Geerkens
  • 11,775
  • 2
  • 32
  • 52
1

You want to do the Knuth/Fisher-Yates shuffle with the characters of the string.

Here are a bunch of C# implementations which you can adapt to a string instead of an array: Is using Random and OrderBy a good shuffle algorithm?

Community
  • 1
  • 1
Andrew Mao
  • 35,740
  • 23
  • 143
  • 224
  • 2
    Fisher-Yates Shuffle is for generating single random permutations, or small sets of such. The OP wants to generate EVERY permutation, for which simple looping algorithms are better suited and more efficient. – Pieter Geerkens Mar 03 '13 at 00:11
  • I don't know...it sounds like he wants to scramble it so that every permutation is possible, not obtain every possible permutation. Perhaps question is unclear. – Andrew Mao Mar 03 '13 at 00:22
  • 1
    I am looking for every possible variation of the 4 words in the string...not characters. – Jeagr Mar 03 '13 at 00:24
  • 1
    1) Build an array of the words. (2) Generate an array of the permutations of N, the number of words. (3) loop through the second array writing out the generated combinations one per line. – Pieter Geerkens Mar 03 '13 at 00:29
1

Here's a full sample program:

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApplication2
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            var sentences = new List<string>
            {
                "Little Red Riding Hood",
                "Three Little Pigs",
                "Jack and the Beanstalk"
            };

            foreach (var sentence in sentences)
            {
                Console.WriteLine("----------------------------------");

                foreach (var permutation in Permute(sentence.Split(' ')))
                {
                    foreach (string word in permutation)
                    {
                        Console.Write(word + " ");
                    }

                    Console.WriteLine();
                }
            }

            // If you want to put all the permutations for all the sentences into a List<string>, you can just do this:

            List<string> permutations = new List<string>();

            foreach (var sentence in sentences)
            {
                permutations.AddRange(Permute(sentence.Split(' ')).Select(perm => string.Join(" ", perm)));
            }

            Console.WriteLine("The total number of perms is: " + permutations.Count);
        }

        /// <summary>
        /// Provides a sequence of enumerators for obtaining all permutations of a sequence.
        /// Each enumeration in the returned sequence itself enumerates one of the permutations of the input sequence.
        /// Use two nested foreach statements to visit each item in each permuted sequence.
        /// </summary>

        public static IEnumerable<IEnumerable<T>> Permute<T>(IEnumerable<T> sequence)
        {
            return permute(sequence, sequence.Count());
        }

        // Returns an enumeration of enumerators, one for each permutation of the input.

        private static IEnumerable<IEnumerable<T>> permute<T>(IEnumerable<T> sequence, int count)
        {
            if (count == 0)
            {
                yield return new T[0];
            }
            else
            {
                int startingElementIndex = 0;

                foreach (T startingElement in sequence)
                {
                    IEnumerable<T> remainingItems = allExcept(sequence, startingElementIndex);

                    foreach (IEnumerable<T> permutationOfRemainder in permute(remainingItems, count - 1))
                    {
                        yield return concat<T>(new T[] { startingElement }, permutationOfRemainder);
                    }

                    ++startingElementIndex;
                }
            }
        }

        // Implements the recursive part of Permute<T>

        private static void permute<T>(T[] items, int item, T[] permutation, bool[] used, Action<T[]> output)
        {
            for (int i = 0; i < items.Length; ++i)
            {
                if (!used[i])
                {
                    used[i] = true;
                    permutation[item] = items[i];

                    if (item < (items.Length - 1))
                    {
                        permute(items, item + 1, permutation, used, output);
                    }
                    else
                    {
                        output(permutation);
                    }

                    used[i] = false;
                }
            }
        }

        // Enumerates over all items in the input, skipping over the item with the specified index.

        private static IEnumerable<T> allExcept<T>(IEnumerable<T> input, int indexToSkip)
        {
            int index = 0;

            foreach (T item in input)
            {
                if (index != indexToSkip)
                {
                    yield return item;
                }

                ++index;
            }
        }

        // Enumerates over contents of two lists sequentially.

        private static IEnumerable<T> concat<T>(IEnumerable<T> a, IEnumerable<T> b)
        {
            foreach (T item in a)
            {
                yield return item;
            }

            foreach (T item in b)
            {
                yield return item;
            }
        }
    }
}
Matthew Watson
  • 104,400
  • 10
  • 158
  • 276
  • Matthew, so if I had multiple strings (each with multiple words), I would create a list, and then for each item in the list run this algo? – Jeagr Mar 03 '13 at 00:35
  • 1
    Do you mean that you want to take all the words in all the lists, and generate all the possible permutations of all the words together? Or do you mean that you want to generate all possible combinations of words taken from the different lists? (i.e. for the combinations, given the two lists "a b c" and "d e" you would generate "a d", "a e", "b d", "b e", "c d", "c e") – Matthew Watson Mar 03 '13 at 00:38
  • For each string in the list, of which "Little Red Riding Hood" would be one, call the function and the function returns all word permutations for that string. Basically, do something like this: theList.ForEach(scramble); – Jeagr Mar 03 '13 at 00:41
  • 1
    Yes, so you just need another outer foreach to traverse the list of space-separated strings, and use each string as input. I'll update my code sample to demonstrate. – Matthew Watson Mar 03 '13 at 00:43
  • SO, if I am trying to add the returned values to a new list, would I replace the "Console.Write(word + " ");" with something like "var combine = word + " "; – Jeagr Mar 03 '13 at 00:55
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/25445/discussion-between-jeagr-and-matthew-watson) – Jeagr Mar 03 '13 at 00:56
  • Yes, I see now. Thank you Matthew! – Jeagr Mar 03 '13 at 01:06