1

if I have two array

A:[A,B] 
B:[1,2,3]

how can I create a string List like [A_1, A_2, A_3, B_1, B_2, B_3]

the number of array is not regular, it's maybe have 3 more

A:[A,B] 
B:[1,2,3]
C:[w,x,y,z]
D:[m,n]
E:[p,q,r]

can I use recursive to solve it?

Papago Kuo
  • 23
  • 4
  • 10
    Why do you show pseudo-code? That makes it more difficult to understand what you're trying to achieve. The types are also not clear. – Tim Schmelter Aug 14 '14 at 07:42
  • What would you expect the output to be for your second example? is it enough to just reverse the lists, take two lists at a time and prefix them with the next list? – Sayse Aug 14 '14 at 07:48
  • Can we start with an array-of-arrays? That would make it easier. – Matthew Watson Aug 14 '14 at 07:50
  • @MatthewWatson: i'm not sure if OP means that the number of arrays is unknown but the number of elements in the arrays. I guess you're overcomplicating this question. – Tim Schmelter Aug 14 '14 at 07:54
  • I think he does mean the number of arrays is unknown, since he gives 2 examples with different numbers of elements and different number of arrays.. – James Aug 14 '14 at 07:55
  • @judgeja: the second _example_ could also be the desired result and the `C`-list just a generic way to express `A_1, A_2, A_3, B_1, B_2, B_3`. **Edit** Now it's more clear ;) – Tim Schmelter Aug 14 '14 at 07:57
  • This one is not easy to answer because it is not really clear what you want. Is use of recursion really needed and if so, why? How many arrays are there and how should those be merged? What data types are used for the arrays? What did you try already? Furthermore show some source code and not pseudo code. – T_D Aug 14 '14 at 07:58
  • I have edited [my answer](http://stackoverflow.com/a/25302636/284240) to provide a solution that works with `IEnumerable>`. But OP should edit his question if he really wants all combinations. He also should show the desired result for the 5 arrays. It could be `A_1, A_2, A_3, B_1, B_2, B_3 , ...` or `A_1_w_m_p, A_1_w_m_1, A_1_w_m_r, ...`. – Tim Schmelter Aug 14 '14 at 08:36

5 Answers5

0

This is simple iterating over n-ary dimension - no need for recursion for that, just array to store indexes.

static void Iterate(int[] iterators, ArrayList[] arrays) {
  for (var j = iterators.Length - 1; j >= 0; j--) {
    iterators[j]++;
    if (iterators[j] == arrays[j].Count) {
      if (j == 0) {
        break;
      }
      iterators[j] = 0;
    } else {
      break;
    }
  }

}
static IList<string> Merge(ArrayList[] arrays) {
  List<string> result = new List<string>();
  int[] iterators = new int[arrays.Length];
  while (iterators[0] != arrays[0].Count) {
    var builder = new StringBuilder(20);
    for(var index = 0; index < arrays.Length; index++) {
      if (index > 0) {
        builder.Append("_");
      }
      builder.Append(arrays[index][iterators[index]]);
    }
    result.Add(builder.ToString());
    Iterate(iterators, arrays);
  }
  return result;
}

static void Main(string[] args) {
  var list1 = new ArrayList();
  var list2 = new ArrayList();
  var list3 = new ArrayList();

  list1.Add(1);
  list1.Add(2);
  list2.Add("a");
  list2.Add("b");
  list3.Add("x");
  list3.Add("y");
  list3.Add("z");

  var result = Merge(new[] { list1, list2, list3 });
}
Ondrej Svejdar
  • 21,349
  • 5
  • 54
  • 89
0
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace arrconn {
    class Program {
        static string[] conn(params Array[] arrs) {
            if(arrs.Length == 0) return new string[0];
            if(arrs.Length == 1) {
                string[] result = new string[arrs[0].Length];
                for(int i = 0; i < result.Length; i++)
                    result[i] = arrs[0].GetValue(i).ToString();
                return result; }
            else {
                string[] result = new string[arrs[0].Length*arrs[1].Length];
                for(int i = 0; i < arrs[0].Length; i++)
                    for(int j = 0; j < arrs[1].Length; j++)
                        result[i*arrs[1].Length+j] = string.Format("{0}_{1}", arrs[0].GetValue(i), arrs[1].GetValue(j));
                if(arrs.Length == 2) return result;
                Array[] next = new Array[arrs.Length-1];
                next[0] = result; Array.Copy(arrs, 2, next, 1, next.Length-1);
                return conn(next);
            }
        }
        static void Main(string[] args) {
            foreach(string s in  conn(
                new string[] { "A", "B" },
                new int[] { 1, 2, 3 },
                new string[] { "x" },
                new string[] { "$", "%", "#" }))
                Console.WriteLine(s);
            Console.Read();
        }
    }
}
firda
  • 3,268
  • 17
  • 30
0

So, we define a functions Mergethat takes lists of list of stings and merges them into the string enumerable you want

static void Main(string[] args)
{
    var a = new[] { "A", "B" };
    var b = new[] { "1", "2", "3" };
    var c = new[] { "x", "y", "z", "w" };

    var result = Merge(a, b, c);
    foreach (var r in result)
    {
        Console.WriteLine(r);
    }
}

public static IList<string> Merge(params IEnumerable<string>[] lists)
{
    return Merge((IEnumerable<IEnumerable<string>>) lists);
}

public static IList<string> Merge(IEnumerable<IEnumerable<string>> lists)
{
    var retval = new List<string>();
    var first = lists.FirstOrDefault();
    if (first != null)
    {
        var result = Merge(lists.Skip(1));
        if (result.Count > 0)
        {
            foreach (var x in first)
            {                
                retval.AddRange(result.Select(y => string.Format("{0}_{1}", x, y)));
            }
        }                
        else
        {
            retval.AddRange(first);
        }            
    }

    return retval;
}

we can also improve this, if you use Lists as inputs

public static IList<string> Merge(params IList<string>[] lists)
{
    return Merge((IList<IList<string>>) lists);
}

public static IList<string> Merge(IList<IList<string>> lists, int offset = 0)
{
    if (offset >= lists.Count)
        return new List<string>();

    var current = lists[offset];
    if (offset + 1 == lists.Count) // last entry in lists
        return current;

    var retval = new List<string>();

    var merged = Merge(lists, offset + 1);
    foreach (var x in current)
    {
        retval.AddRange(merged.Select(y => string.Format("{0}_{1}", x, y)));
    }

    return retval;
}
esskar
  • 10,638
  • 3
  • 36
  • 57
0

I guess your input are like this:

var A = ["A","B"];
var B = [1,2,3];
var C = ["x","y","z","w"];

And what you want to obtain is:

var result = ["A_1_x", "A_1_y",...
    "A_2_x", "A_2_y",...
    "A_3_x", "A_3_y",...
    "B_1_x", "B_1_y",...
    ...
    ..., "B_3_z", "B_3_w"];

We'll be working with IEnumerable as it will simplify the work for us and give us access to the yield keyword. First, let's take care of the case where we only concataining two collections:

IEnumerable<string> ConcatEnumerables(IEnumerable<object> first, IEnumerable<object> second)
{
    foreach (var x in first)
    {
        foreach (var y in second)
        {
            yield return x.ToString() + "_" + y.ToString();
        }
    }
}

Then we can recursively takle any number of collections:

IEnumerable<string> ConcatEnumerablesRec(IEnumerable<IEnumerable<object>> enums)
{            
    //base cases
    if(!enums.Any())
    {
        return Enumerable.Empty<string>();
    }
    if (enums.Count() == 1)
    {
        return enums.First().Select(o => o.ToString());
    }

    //recursively solve the problem
    return ConcatEnumerables(enums.First(), ConcatEnumerablesRec(enums.Skip(1));
}

Now you just need to call ToArray on the result if you really need an array as your output.

string[] Concatenator(params object[][] parameters)
{
    return ConcatEnumerablesRec(parameters).ToArray();
}
Falanwe
  • 4,636
  • 22
  • 37
0

This should do the trick. Note that the input sequences do not have to be arrays - they can be any type that implements IEnumerable<>.

Also note that we have to case sequences of value types to sequences of <object> so that they are assignable to IEnumerable<object>.

Here's the compilable Console app demo code:

using System;
using System.Collections.Generic;
using System.Linq;

namespace Demo
{
    internal static class Program
    {
        static void Main()
        {
            string[] a = {"A", "B", "C", "D"};
            var      b = Enumerable.Range(1, 3); // <-- See how it doesn't need to be an array.
            char[]   c = {'X', 'Y', 'Z'};
            double[] d = {-0.1, -0.2};

            var sequences = new [] { a, b.Cast<object>(), c.Cast<object>(), d.Cast<object>() };

            Console.WriteLine(string.Join("\n", Combine("", sequences)));
        }

        public static IEnumerable<string> Combine(string prefix, IEnumerable<IEnumerable<object>> sequences)
        {
            foreach (var item in sequences.First())
            {
                string current = (prefix == "") ? item.ToString() : prefix + "_" + item;
                var remaining = sequences.Skip(1);

                if (!remaining.Any())
                {
                    yield return current;
                }
                else
                {
                    foreach (var s in Combine(current, remaining))
                        yield return s;
                }
            }
        }
    }

}
Matthew Watson
  • 104,400
  • 10
  • 158
  • 276