如何使用yield return和recursion获取每个字母组合?

我有几个字符串列表,从几十个可能的列表:

1: { "A", "B", "C" } 2: { "1", "2", "3" } 3: { "D", "E", "F" } 

这三个仅作为示例选择,并且用户可以从具有不同数量的元素的数十个类似列表中进行选择。 再举一个例子,这对用户来说也是一个非常有效的选择:

 25: { } // empty 4: { "%", "!", "$", "@" } 16: { "I", "a", "b", "Y" } 8: { ")", "z", "!", "8" } 

我想要做的是在保持列表的“顺序”的同时获得每个字符串组合。 换句话说,假设我们正在查看第一个列表,第一个组合将是A1D ,然后是A1E ,然后是A1F ,然后是B1D ,然后是B1E ,依此类推。 到目前为止,我已经编写了这个递归算法:

 public void Tester() { var 2dList = new List { list1, list2, list3 }; var answer = ReturnString(2dList).ToList(); answer.ForEach(Console.WriteLine); } public IEnumerable ReturnString(List<List> list) { if (!list.Any()) { yield return null; } else { // for each letter in the top-most list... foreach (var letter in list.First()) { // get the remaining lists minus the first one var nextList = list.Where(x => x != list.First()).ToList(); // get the letter and recurse down to find the next yield return letter + ReturnString(nextList); } } } 

但是,我得到的回报是:

 AStringGeneration.StringGenerator+d__11 BStringGeneration.StringGenerator+d__11 CStringGeneration.StringGenerator+d__11 

StringGenerationReturnString所在类的名称。当我在yield return letter + ...行上放置一个断点时,它似乎迭代了ABC ,但实际上并没有递归。 我不确定这里发生了什么。 任何人都可以解释我的算法有什么问题吗?

你需要枚举迭代器:

 foreach(string s in ReturnString(...)) { Console.WriteLine(s); } 

这也适用于每次迭代:

 foreach(string tail in ReturnString(nextList)) yield return letter + tail; 

另外,我怀疑你可以在这里用SelectMany做点什么。

 from x in l1 from y in l2 from z in l3 select x + y + + z 

更新:

这是一个任意版本的大纲。 我稍后会详细说明。

 private bool m_beforeStart; private IList> m_lists; private Stack> m_enumerators; public bool MoveNext() { while (CurrentEnumerator != null && !CurrentEnumerator.MoveNext()) { RemoveLastChar(m_stringBuilder); PopEnumerator(); } if (CurrentEnumerator == null && ! m_beforeStart) { return false; } m_beforeStart = false; while (PushEnumerator()) { if (!CurrenEnumerator.MoveNext()) { ClearEnumerators(); return false; } m_stringBuilder.Append( m_currentEnumerator.Current ); } return true; } public string Current { get { return m_stringBuilder.ToString(); } } private IEnumerator CurrentEnumerator { get { return m_enumerators.Count != 0 ? m_enumerators.Peek() : null; } } private void PopEnumerator() { if (m_enumerators.Count != 0) { m_enumerators.Pop(); } } private bool PushEnumerator() { if (m_enumerators.Count == m_lists.Count) { return false; } m_enumerators.Push(m_lists[m_enumerators.Count].GetEnumerator()); } 
 public static IEnumerable ReturnString(IEnumerable> matrix) { if (matrix.Count() == 1) return matrix.First(); return from letter in matrix.First() // foreach letter in first list let tail = matrix.Skip(1) // get tail lists let tailStrings = ReturnString(tail) // recursively build lists of endings for each tail from ending in tailStrings // foreach string in these tail endings select letter + ending; // append letter from the first list to ending } 

调用ReturnString(lst.Where(l => l.Any())跳过空序列。