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

时间:2011-07-31 13:55:24

标签: c# recursion string-concatenation yield-return

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

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,然后是{{1 }}, 等等等等。到目前为止,我已经编写了这个递归算法:

B1E

但是,我得到的回报是:

public void Tester()
{
    var 2dList = new List { list1, list2, list3 };
    var answer = ReturnString(2dList).ToList();

    answer.ForEach(Console.WriteLine);
}

public IEnumerable<string> ReturnString(List<List<string>> 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+<ReturnString>d__11 BStringGeneration.StringGenerator+<ReturnString>d__11 CStringGeneration.StringGenerator+<ReturnString>d__11 StringGeneration所在类的名称。当我在ReturnString行上设置断点时,它似乎会遍历yield return letter + ...,{{ 1}}和A,但实际上没有递归。我不确定这里发生了什么。任何人都可以解释我的算法有什么问题吗?

3 个答案:

答案 0 :(得分:3)

您需要枚举迭代器:

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

这也适用于每次迭代:

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

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

答案 1 :(得分:3)

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

<强>更新

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

private bool m_beforeStart;
private IList<IEnumerable<char>> m_lists;
private Stack<IEnumerator<char>> 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<char> 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());
}

答案 2 :(得分:1)

public static IEnumerable<string> ReturnString(IEnumerable<IEnumerable<string>> 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())跳过空序列。