开发者

Combining arrays of strings together

I'm looking to combine the contents of two string a开发者_StackOverflow社区rrays, into a new list that has the contents of both joined together.

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...

How can I do it ? For when it's only two arrays, the following works and is easy enough:

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;
}

But I'd like to be able to pass varying numbers of arrays in (i.e. to have a method with the signature below) and have it still work.

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

Or some other solution would be great. If it's possible to do this simply with Linq, even better!


What you want to do is actually a cartesian product of all the arrays of words, then join the words with spaces. Eric Lippert has a simple implementation of a Linq cartesian product here. You can use it to implement CombineWords:

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


To cross join on any amount of arrays of strings:

// 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();
}


Code below works for any number of arrays (and uses linq to some degree):

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();
 }


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;
}

Second try... I'm not able to do it in LINQ... A little too much complex to linquize correctly :-)

I'm using a local anonymous function (and showing that it's quite complex to recurse on anonymous functions, because you have to declare them separately)


This is a non-recursive solution which buffers strings as it progresses, to reduce the number of concatenations. Therefore it should also be usable for more arrays. It also preserves your desired order - the items in the first array will always be at the beginning of the resulting string.

  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);

And the function in question:

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;
}


Could you try this method ?

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;
}

Kris

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜