Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>LINQ can do almost anything - although I had to introduce a constraint that words can only appear once in any chain otherwise I kept getting stack overflow errors.</p> <pre><code>var words = new[] { "old", "dairy", "yellow", "world", "dog", "dad", "yard", "yolk", "yeah", "king", "weld", "goat", "hello", }; Func&lt;IEnumerable&lt;IEnumerable&lt;string&gt;&gt;, IEnumerable&lt;string&gt;, IEnumerable&lt;IEnumerable&lt;string&gt;&gt;&gt; lengthenChains = (css, ws) =&gt; { var endsWith = from cs in css select new { Letter = cs.Last().Last(), Chain = cs, }; var startsWith = from w in ws select new { Letter = w.First(), Word = w, }; return from ew in endsWith join sw in startsWith on ew.Letter equals sw.Letter where ew.Chain.Contains(sw.Word) == false select ew.Chain.Concat(new[] { sw.Word }); }; Func&lt;IEnumerable&lt;string&gt;, IEnumerable&lt;IEnumerable&lt;string&gt;&gt;&gt; makeChain = ws =&gt; from w in ws select (new[] { w, }).AsEnumerable(); Func&lt;IEnumerable&lt;IEnumerable&lt;string&gt;&gt;, IEnumerable&lt;string&gt;, IEnumerable&lt;IEnumerable&lt;string&gt;&gt;&gt; makeChains = null; makeChains = (css, ws) =&gt; css.Any() ? css.Concat(makeChains(lengthenChains(css, ws), ws)) : Enumerable.Empty&lt;IEnumerable&lt;string&gt;&gt;(); var chains = from cs in makeChains(makeChain(words), words) select String.Join(", ", cs.ToArray()); chains.Run(chain =&gt; Console.WriteLine(chain)); </code></pre> <p>I'll leave it for you to get the maximum length chain. It wasn't clear from your question if the length of the chain is a count of the number of words or if it is the character length of the concatenated words.</p> <p>Here's the last 8 that get generated from the above code:</p> <pre><code>yellow, world, dairy, yeah, hello, old, dad, dog, goat yellow, world, dad, dairy, yeah, hello, old, dog, goat yellow, weld, dairy, yeah, hello, old, dad, dog, goat yellow, weld, dad, dairy, yeah, hello, old, dog, goat yeah, hello, old, dairy, yellow, world, dad, dog, goat yeah, hello, old, dairy, yellow, weld, dad, dog, goat yeah, hello, old, dad, dairy, yellow, world, dog, goat yeah, hello, old, dad, dairy, yellow, weld, dog, goat </code></pre> <p>Enjoy.</p> <hr> <p>Roly wanted more of a "prolog backtracking algorithm" - although his question didn't say that! ;-)</p> <p>Here it is:</p> <pre><code>var starting = from w in words let c = (new[] { w }).AsEnumerable() select new Working(c.ToArray(), words.Except(c).ToArray()); var chains = (from cs in Chains(starting) select String.Join(", ", cs.ToArray())).ToArray(); IEnumerable&lt;IEnumerable&lt;string&gt;&gt; Chains(IEnumerable&lt;Working&gt; workings) { foreach (var w in workings) { yield return w.Chain; var last = w.Chain.Last().Last(); var nexts = (from r in w.Remaining where r.First() == last let c = (new[] { r }).AsEnumerable() select new Working(w.Chain.Concat(c).ToArray(), w.Remaining.Except(c).ToArray())); foreach (var chain in Chains(nexts)) { yield return chain; } } } </code></pre> <p>This method is backtracking by using an iterator method, the CLR stack, and recursive calls. Prolog would do this more elegantly, but it turns out my comment on the probable efficiency of this method was wrong. It's actually about two times quicker than my first method.</p> <p>I also feel that this second method is straying further from the use of "pure" LINQ, but it is cleaner, smaller and more efficient. I know I'd rather maintain this version.</p> <p>Oh, the <code>Working</code> class (used to track the working state) is essentially this:</p> <pre><code>class Working { string[] Chain { get; set; } string[] Remaining { get; set; } } </code></pre> <p>The output from this approach clearly shows that it is backtracking:</p> <pre><code>... yeah, hello, old, dog yeah, hello, old, dog, goat yeah, hello, old, dad yeah, hello, old, dad, dairy yeah, hello, old, dad, dairy, yellow yeah, hello, old, dad, dairy, yellow, world yeah, hello, old, dad, dairy, yellow, world, dog yeah, hello, old, dad, dairy, yellow, world, dog, goat yeah, hello, old, dad, dairy, yellow, weld yeah, hello, old, dad, dairy, yellow, weld, dog yeah, hello, old, dad, dairy, yellow, weld, dog, goat yeah, hello, old, dad, dairy, yard yeah, hello, old, dad, dairy, yard, dog yeah, hello, old, dad, dairy, yard, dog, goat yeah, hello, old, dad, dairy, yolk yeah, hello, old, dad, dairy, yolk, king yeah, hello, old, dad, dairy, yolk, king, goat yeah, hello, old, dad, dog yeah, hello, old, dad, dog, goat ... </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload