【问题标题】:Combining arrays of strings together将字符串数组组合在一起
【发布时间】:2011-11-30 13:19:51
【问题描述】:

我希望将两个字符串数组的内容合并到一个新列表中,该列表将两者的内容连接在一起。

string[] days = { "Mon", "Tue", "Wed" };
string[] months = { "Jan", "Feb", "Mar" };

// I want the output to be a list with the contents
// "Mon Jan", "Mon Feb", "Mon Mar", "Tue Jan", "Tue Feb" etc...

我该怎么做?因为当它只有两个数组时,以下工作很简单:

List<string> CombineWords(string[] wordsOne, string[] wordsTwo)
{
    var combinedWords = new List<string>();
    foreach (var wordOne in wordsOne)
    {
        foreach (string wordTwo in wordsTwo)
        {
            combinedWords.Add(wordOne + " " + wordTwo);
        }
    }
    return combinedWords;
}

但我希望能够传入不同数量的数组(即有一个带有下面签名的方法)并让它仍然有效。

List<string> CombineWords(params string[][] arraysOfWords)
{
    // what needs to go here ?
}

或者其他一些解决方案会很棒。如果可以简单地使用 Linq 做到这一点,那就更好了!

【问题讨论】:

  • params string[] 表示“不同数量的 字符串,而不是数组。params string[][] 是您所需要的。
  • 您已将方法的签名更改为static List&lt;string&gt; CombineWords(IEnumerable&lt;string[]&gt; arraysOfWords),因为params string[] arraysOfWords 表示1 个或多个string 类型的参数
  • 谢谢,'params string[][]' 就是我的意思。我已经对其进行了编辑以显示这一点。

标签: c# .net arrays linq


【解决方案1】:

你想要做的实际上是所有单词数组的笛卡尔积,然后用空格连接单词。 Eric Lippert 有一个 Linq 笛卡尔积 here 的简单实现。你可以用它来实现CombineWords:

List<string> CombineWords(params string[][] arraysOfWords)
{
    return CartesianProduct(arraysOfWords)
            .Select(x => string.Join(" ", x))
            .ToList();
}

【讨论】:

    【解决方案2】:

    在任意数量的字符串数组上交叉连接:

    // Define other methods and classes here
    List<string> CombineWords(params string[][] arraysOfWords)
    {
        if (arraysOfWords.Length == 0)
            return new List<string>();
    
        IEnumerable<string> result = arraysOfWords[0];
    
        foreach( string[] words in arraysOfWords.Skip(1) )
        {
            var tempWords = words;
    
            result = from r in result
                     from w in tempWords 
                     select string.Concat(r, " ", w);
        }
    
        return result.ToList();
    }
    

    【讨论】:

    • 谢谢,但与 Thomas Levesque 或 Lucasus 的答案相比,当传入 3 个或更多数组时,这似乎给出的结果较少。
    • 感谢您指出这一点。我为删除对 ToList 的额外调用所做的更改实际上破坏了它,由于我相信延迟执行,需要一个临时变量。 @Lucasus 已经说明了这一点,他的答案很好:) 更新了我的答案以修复错误并避免混淆。
    【解决方案3】:

    以下代码适用于任意数量的数组(并在某种程度上使用 linq):

    List<string> CombineWords(params string[][] wordsToCombine)
    {
         if (wordsToCombine.Length == 0)
             return new List<string>();
    
         IEnumerable<string> combinedWords = wordsToCombine[0].ToList();
         for (int i = 1; i < wordsToCombine.Length; ++i)
         {
             var temp = i;
             combinedWords = (from x in combinedWords from y in wordsToCombine[temp]
                           select x + " " + y);
         }
         return combinedWords.ToList();
     }
    

    【讨论】:

    • Snap,看起来我们想出了类似的东西:)
    • 在将其重构为不需要 .ToList() 调用后,速度非常快(我对其进行了基准测试,速度是 Thomas Levesque 解决方案的两倍)所以正是我想要的 - 非常感谢!
    【解决方案4】:
    public static List<string> CombineWords(params string[][] arraysOfWords)
    {
        var strings = new List<string>();
    
        if (arraysOfWords.Length == 0)
        {
            return strings;
        }
    
        Action<string, int> combineWordsInternal = null;
    
        combineWordsInternal = (baseString, index) =>
        {
            foreach (var str in arraysOfWords[index])
            {
                string str2 = baseString + " " + str;
    
                if (index + 1 < arraysOfWords.Length)
                {
                    combineWordsInternal(str2, index + 1);
                }
                else
                {
                    strings.Add(str2);
                }
            }
        };
    
        combineWordsInternal(string.Empty, 0);
    
        return strings;
    }
    

    第二次尝试...我无法在 LINQ 中执行此操作...有点太复杂而无法正确 linquize :-)

    我正在使用本地匿名函数(并表明递归匿名函数非常复杂,因为您必须单独声明它们)

    【讨论】:

    • 您可能想再次阅读问题,您的答案与@mikel 的要求无关。问题与工会无关。
    • @ANeves 我反对内部方法。但是我可以使用本地函数:-) :-)
    • 有点复杂,这意味着可维护性较差,但对我有用。
    • @ANeves 这取决于...如果您是 Javascript“血统”,这将尽可能清晰 :-)
    【解决方案5】:

    这是一个非递归解决方案,它在字符串进行时缓冲字符串,以减少连接的数量。因此,它也应该可用于更多阵列。 它还保留了您想要的顺序 - 第一个数组中的项目将始终位于结果字符串的开头。

      var s1 = new string[] { "A", "B", "C" };
      var s2 = new string[] { "1", "2", "3", "4" };
      var s3 = new string[] { "-", "!", "?" };
      var res = Combine(s1, s2, s3);
    

    以及相关功能:

    private List<string> Combine(params string[][] arrays)
    {
        if (arrays.Length == 1)
        {
            // The trivial case - exit.
            return new List<string>(arrays[0]);
        }
        IEnumerable<string> last = arrays[arrays.Length - 1];
        // Build from the last array, progress forward
        for (int i = arrays.Length - 2; i >= 0; i--)
        {
            var buffer = new List<string>();
            var current = arrays[i];
            foreach (var head in current)
            {
                foreach (var tail in last)
                {
                    // Concatenate with the desired space.
                    buffer.Add(head + " " + tail);
                }
            }
            last = buffer;
        }
        return (List<string>)last;
    }
    

    【讨论】:

      【解决方案6】:

      你可以试试这个方法吗?

      static List<string> CombineWords(string[] wordsOne, string[] wordsTwo)
      {
          var combinedWords = new List<string>();
          for(int x = 0; (x <= wordsOne.Length - 1); ++x)
          {
              for(int y = 0; (x <= wordsTwo.Length - 1); ++y)
              {
                  combinedWords.Add(string.Format("{0} {1}", wordsOne[x], wordsTwo[y]));
              }
          }
          return combinedWords;
      }
      

      克里斯

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-12-24
        • 2015-01-28
        • 1970-01-01
        • 1970-01-01
        • 2011-04-30
        • 2020-01-28
        • 1970-01-01
        • 2016-07-28
        相关资源
        最近更新 更多