Iterating non-square (sort of) matrix - c#

I have a dictionary like this (sample data thus it doesn't make sense):
Dictionary<char, string[]> codes = new Dictionary<char, string[]>();
string[] is an array of possible replacements for the Dictionary's key.
Filling up the dictionary with some sample data...
codes.Add("A", new string[] {"噅噅", "裧", "頖", "11"});
codes.Add("B", new string[] {"垥", "2", "鉠"});
codes.Add("C", new string[] {"33", "韎"});
codes.Add("D", new string[] {"櫋", "緟", "嘕", "鈖", "灡", "犅"});
...
codes.Add("T", new string[] {"濇", "汫", "岕", "5"});
...
Now lets "encode" the following word:
char[] charArray = "act".ToCharArray();
foreach (char c in charArray) {
string[] replacements = codes[c].Where(x => !String.IsNullOrEmpty(x)).ToArray();//removing empty elements
...
}
I cannot wrap my head now on what to do next, I want to have a list of all possible combinations, it should return a list like this (for the word "act"):
噅噅韎5
裧33濇
裧33汫
裧33岕
裧335
裧韎濇
裧韎汫
裧韎岕
...
Can't show all combinations because of stackoverflow's spam filter...

The post title is misleading. If I understand correctly, you want to generate all the combinations using the codes as input char replacements.
I have answered a similar question (String combinations with multi-character replacement), however due to string[] part I cannot reuse directly the handy code from Looking at each combination in jagged array, so instead I'll just utilize the same algorithm for your case:
public static class Algorithms
{
public static IEnumerable<string> GetCombinations(this string input, Dictionary<char, string[]> replacements)
{
var map = new string[input.Length][];
for (int i = 0; i < map.Length; i++)
{
var c = input[i];
string[] r;
map[i] = replacements.TryGetValue(c, out r)
&& (r = r.Where(s => !string.IsNullOrEmpty(s)).ToArray()).Length > 0 ?
r : new string[] { c.ToString() };
}
int maxLength = map.Sum(output => output.Max(s => s.Length));
var buffer = new char[maxLength];
int length = 0;
var indices = new int[input.Length];
for (int pos = 0, index = 0; ;)
{
for (; pos < input.Length; pos++, index = 0)
{
indices[pos] = index;
foreach (var c in map[pos][index])
buffer[length++] = c;
}
yield return new string(buffer, 0, length);
do
{
if (pos == 0) yield break;
index = indices[--pos];
length -= map[pos][index].Length;
}
while (++index >= map[pos].Length);
}
}
}
Test:
var codes = new Dictionary<char, string[]>();
codes.Add('A', new string[] { "噅噅", "裧", "頖", "11" });
codes.Add('B', new string[] { "垥", "2", "鉠" });
codes.Add('C', new string[] { "33", "韎" });
codes.Add('D', new string[] { "櫋", "緟", "嘕", "鈖", "灡", "犅" });
//...
codes.Add('T', new string[] { "濇", "汫", "岕", "5" });
//...
var test = "ACT".GetCombinations(codes).ToList();

Related

Searching for words in a string and comparing them

I can't come up with a word search code that would still output the word when the position of the word changes
class Program
{
static void Main(string[] arg)
{
Console.OutputEncoding = System.Text.Encoding.Unicode;
Console.InputEncoding = System.Text.Encoding.Unicode;
var srd = new MultiSet<Garders>()
{
new Garders("ірис, троянда, айстра, півонія, жоржин"),
new Garders("ірис, троянда, айстра, півонія, жоржин, хризантема, гладіолус"),
new Garders("ірис, троянда, айстра, півонія, гладіолус")
};
MultiSet<Garders>.Enumerator e = srd.GetEnumerator();
string[] temp = new string[3];
for (int i = 0; i < temp.Length; i++)
{
e.MoveNext();
temp[i] = e.Current.flower;
}
e.Reset();
while (e.MoveNext())
{
string[] srt = e.Current.flower.Split();
foreach (var item in srt)
{
if (temp[0].Contains(item) == temp[1].Contains(item)
&& temp[1].Contains(item) == temp[2].Contains(item))
Console.WriteLine(item);
}
Console.WriteLine();
}
}
}
}
My code only outputs the same words if they are in the same positions
You have written very complex logic, it should be very easy if you read the problem statement carefully.
Based on the discussion in a comment, you want to compare two collections whether they have the same items in the same order.
You could use List.
and compare like this.
List<string> ls1 = new List<string>() { "1", "2"};
List<string> ls2 = new List<string>() { "1", "2" };
bool isEqual = ls1.SequenceEqual(ls2);

Connect element in distinct array using recursion

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

Need help on a simple string sort method from a string array

seriously need some guideline on string sorting methodology. Perhaps, if able to provide some sample code would be a great help. This is not a homework. I would need this sorting method for concurrently checking multiple channel names and feed the channel accordingly based on the sort name/string result.
Firstly I would have the string array pattern something like below:
string[] strList1 = new string[] {"TDC1ABF", "TDC1ABI", "TDC1ABO" };
string[] strList2 = new string[] {"TDC2ABF", "TDC2ABI", "TDC2ABO"};
string[] strList3 = new string[] {"TDC3ABF", "TDC3ABO","TDC3ABI"}; //2nd and 3rd element are swapped
I would like to received a string[] result like below:
//result1 = "TDC1ABF , TDC2ABF, TDC3ABF"
//result2 = "TDC1ABI , TDC2ABI, TDC3ABI"
//result3 = "TDC1ABO , TDC2ABO, TDC3ABO"
Ok, here is my idea of doing the sorting.
First, each of the strList sort keyword *ABF.
Then, put all the strings with *ABF into result array.
Finally do Order sort to have the string array align into TDC1ABF, TDC2ABF, TDC3ABF accordingly.
Do the same thing for the other string array inside a loop.
So, my problem is.. how to search *ABF within a string inside a string array?
static void Main()
{
var strList1 = new[] { "TDC1ABF", "TDC1ABI", "TDC1ABO" };
var strList2 = new[] { "TDC2ABF", "TDC2ABI", "TDC2ABO" };
var strList3 = new[] { "TDC3ABF", "TDC3ABO", "TDC3ABI" };
var allItems = strList1.Concat(strList2).Concat(strList3);
var abfItems = allItems.Where(item => item.ToUpper().EndsWith("ABF"))
.OrderBy(item => item);
var abiItems = allItems.Where(item => item.ToUpper().EndsWith("ABI"))
.OrderBy(item => item);
var aboItems = allItems.Where(item => item.ToUpper().EndsWith("ABO"))
.OrderBy(item => item);
}
If you do something like this then you can compare all the sums and arrange them in order. The lower sums are the ones closer to 1st and the higher are the ones that are farther down.
static void Main(string[] args)
{
string[] strList1 = new string[] { "TDC1ABF", "TDC1ABI", "TDC1ABO" };
string[] strList2 = new string[] { "TDC2ABF", "TDC2ABI", "TDC2ABO" };
string[] strList3 = new string[] { "TDC3ABF", "TDC3ABO", "TDC3ABI" };
arrange(strList1);
arrange(strList2);
arrange(strList3);
}
public static void arrange(string[] list)
{
Console.WriteLine("OUT OF ORDER");
foreach (string item in list)
{
Console.WriteLine(item);
}
Console.WriteLine();
for (int x = 0; x < list.Length - 1; x++)
{
char[] temp = list[x].ToCharArray();
char[] temp1 = list[x + 1].ToCharArray();
int sum = 0;
foreach (char letter in temp)
{
sum += (int)letter; //This adds the ASCII value of each char
}
int sum2 = 0;
foreach (char letter in temp1)
{
sum2 += (int)letter; //This adds the ASCII value of each char
}
if (sum > sum2)
{
string swap1 = list[x];
list[x] = list[x + 1];
list[x + 1] = swap1;
}
}
Console.WriteLine("IN ORDER");
foreach (string item in list)
{
Console.WriteLine(item);
}
Console.WriteLine();
Console.ReadLine();
}
If the arrays are guaranteed to have as many elements as there are arrays then you could sort the individual arrays first, dump the sorted arrays into an nxn array and then transpose the matrix.

Convert array of strings to Dictionary<string, int> c# then output to Visual Studio

I have an array of strings like so:
[0]Board1
[1]Messages Transmitted75877814
[2]ISR Count682900312
[3]Bus Errors0
[4]Data Errors0
[5]Receive Timeouts0
[6]TX Q Overflows0
[7]No Handler Failures0
[8]Driver Failures0
[9]Spurious ISRs0
just to clarify the numbers in the square brackets indicate the strings position in the array
I want to convert the array of strings to a dictionary with the string to the left of each number acting as the key, for example (ISR Count, 682900312)
I then want to output specific entries in the dictionary to a text box/table in visual studio (which ever is better) it would be preferable for the numbers to be left aligned.
excuse my naivety, I'm a newbie!
Pretty Simple. Tried and Tested
string[] arr = new string[] { "Board1", "ISR Count682900312", ... };
var numAlpha = new Regex("(?<Alpha>[a-zA-Z ]*)(?<Numeric>[0-9]*)");
var res = arr.ToDictionary(x => numAlpha.Match(x).Groups["Alpha"],
x => numAlpha.Match(x).Groups["Numeric"]);
string[] strings =
{
"Board1", "Messages232"
};
Dictionary<string, int> dictionary = new Dictionary<string, int>();
foreach (var s in strings)
{
int index = 0;
for (int i = 0; i < s.Length; i++)
{
if (Char.IsDigit(s[i]))
{
index = i;
break;
}
}
dictionary.Add(s.Substring(0, index), int.Parse(s.Substring(index)));
}
var stringArray = new[]
{
"[0]Board1",
"[1]Messages Transmitted75877814",
"[2]ISR Count682900312",
"[3]Bus Errors0",
"[4]Data Errors0",
"[5]Receive Timeouts0",
"[6]TX Q Overflows0",
"[7]No Handler Failures0",
"[8]Driver Failures0",
"[9]Spurious ISRs0"
};
var resultDict = stringArray.Select(s => s.Substring(3))
.ToDictionary(s =>
{
int i = s.IndexOfAny("0123456789".ToCharArray());
return s.Substring(0, i);
},
s =>
{
int i = s.IndexOfAny("0123456789".ToCharArray());
return int.Parse(s.Substring(i));
});
EDIT: If the numbers in brackets are not included in the strings, remove .Select(s => s.Substring(3)).
Here you go:
string[] strA = new string[10]
{
"Board1",
"Messages Transmitted75877814",
"ISR Count682900312",
"Bus Errors0",
"Data Errors0",
"Receive Timeouts0",
"TX Q Overflows0",
"No Handler Failures0",
"Driver Failures0",
"Spurious ISRs0"
};
Dictionary<string, int> list = new Dictionary<string, int>();
foreach (var item in strA)
{
// this Regex matches any digit one or more times so it picks
// up all of the digits on the end of the string
var match = Regex.Match(item, #"\d+");
// this code will substring out the first part and parse the second as an int
list.Add(item.Substring(0, match.Index), int.Parse(match.Value));
}

C# Permutation of an array of arraylists?

I have an ArrayList[] myList and I am trying to create a list of all the permutations of the values in the arrays.
EXAMPLE: (all values are strings)
myList[0] = { "1", "5", "3", "9" };
myList[1] = { "2", "3" };
myList[2] = { "93" };
The count of myList can be varied so its length is not known beforehand.
I would like to be able to generate a list of all the permutations similar to the following (but with some additional formatting).
1 2 93
1 3 93
5 2 93
5 3 93
3 2 93
3 3 93
9 2 93
9 3 93
Does this make sense of what I am trying to accomplish? I can't seem to come up with a good method for doing this, (if any).
Edit:
I am not sure if recursion would interfere with my desire to format the output in my own manner. Sorry I did not mention before what my formatting was.
I want to end up building a string[] array of all the combinations that follows the format like below:
for the "1 2 93" permutation
I want the output to be "val0=1;val1=2;val2=93;"
I will experiment with recursion for now. Thank you DrJokepu
I'm surprised nobody posted the LINQ solution.
from val0 in new []{ "1", "5", "3", "9" }
from val1 in new []{ "2", "3" }
from val2 in new []{ "93" }
select String.Format("val0={0};val1={1};val2={2}", val0, val1, val2)
Recursive solution
static List<string> foo(int a, List<Array> x)
{
List<string> retval= new List<string>();
if (a == x.Count)
{
retval.Add("");
return retval;
}
foreach (Object y in x[a])
{
foreach (string x2 in foo(a + 1, x))
{
retval.Add(y.ToString() + " " + x2.ToString());
}
}
return retval;
}
static void Main(string[] args)
{
List<Array> myList = new List<Array>();
myList.Add(new string[0]);
myList.Add(new string[0]);
myList.Add(new string[0]);
myList[0] = new string[]{ "1", "5", "3", "9" };
myList[1] = new string[] { "2", "3" };
myList[2] = new string[] { "93" };
foreach (string x in foo(0, myList))
{
Console.WriteLine(x);
}
Console.ReadKey();
}
Note that it would be pretty easy to return a list or array instead of a string by changing the return to be a list of lists of strings and changing the retval.add call to work with a list instead of using concatenation.
How it works:
This is a classic recursive algorithm. The base case is foo(myList.Count, myList), which returns a List containing one element, the empty string. The permutation of a list of n string arrays s1, s2, ..., sN is equal to every member of sA1 prefixed to the permutation of n-1 string arrays, s2, ..., sN. The base case is just there to provide something for each element of sN to be concatenated to.
I recently ran across a similar problem in a project of mine and stumbled on this question. I needed a non-recursive solution that could work with lists of arbitrary objects. Here's what I came up with. Basically I'm forming a list of enumerators for each of the sub-lists and incrementing them iteratively.
public static IEnumerable<IEnumerable<T>> GetPermutations<T>(IEnumerable<IEnumerable<T>> lists)
{
// Check against an empty list.
if (!lists.Any())
{
yield break;
}
// Create a list of iterators into each of the sub-lists.
List<IEnumerator<T>> iterators = new List<IEnumerator<T>>();
foreach (var list in lists)
{
var it = list.GetEnumerator();
// Ensure empty sub-lists are excluded.
if (!it.MoveNext())
{
continue;
}
iterators.Add(it);
}
bool done = false;
while (!done)
{
// Return the current state of all the iterator, this permutation.
yield return from it in iterators select it.Current;
// Move to the next permutation.
bool recurse = false;
var mainIt = iterators.GetEnumerator();
mainIt.MoveNext(); // Move to the first, succeeds; the main list is not empty.
do
{
recurse = false;
var subIt = mainIt.Current;
if (!subIt.MoveNext())
{
subIt.Reset(); // Note the sub-list must be a reset-able IEnumerable!
subIt.MoveNext(); // Move to the first, succeeds; each sub-list is not empty.
if (!mainIt.MoveNext())
{
done = true;
}
else
{
recurse = true;
}
}
}
while (recurse);
}
}
You could use factoradics to generate the enumeration of permutations. Try this article on MSDN for an implementation in C#.
This will work no matter how many arrays you add to your myList:
static void Main(string[] args)
{
string[][] myList = new string[3][];
myList[0] = new string[] { "1", "5", "3", "9" };
myList[1] = new string[] { "2", "3" };
myList[2] = new string[] { "93" };
List<string> permutations = new List<string>(myList[0]);
for (int i = 1; i < myList.Length; ++i)
{
permutations = RecursiveAppend(permutations, myList[i]);
}
//at this point the permutations variable contains all permutations
}
static List<string> RecursiveAppend(List<string> priorPermutations, string[] additions)
{
List<string> newPermutationsResult = new List<string>();
foreach (string priorPermutation in priorPermutations)
{
foreach (string addition in additions)
{
newPermutationsResult.Add(priorPermutation + ":" + addition);
}
}
return newPermutationsResult;
}
Note that it's not really recursive. Probably a misleading function name.
Here is a version that adheres to your new requirements. Note the section where I output to console, this is where you can do your own formatting:
static void Main(string[] args)
{
string[][] myList = new string[3][];
myList[0] = new string[] { "1", "5", "3", "9" };
myList[1] = new string[] { "2", "3" };
myList[2] = new string[] { "93" };
List<List<string>> permutations = new List<List<string>>();
foreach (string init in myList[0])
{
List<string> temp = new List<string>();
temp.Add(init);
permutations.Add(temp);
}
for (int i = 1; i < myList.Length; ++i)
{
permutations = RecursiveAppend(permutations, myList[i]);
}
//at this point the permutations variable contains all permutations
foreach (List<string> list in permutations)
{
foreach (string item in list)
{
Console.Write(item + ":");
}
Console.WriteLine();
}
}
static List<List<string>> RecursiveAppend(List<List<string>> priorPermutations, string[] additions)
{
List<List<string>> newPermutationsResult = new List<List<string>>();
foreach (List<string> priorPermutation in priorPermutations)
{
foreach (string addition in additions)
{
List<string> priorWithAddition = new List<string>(priorPermutation);
priorWithAddition.Add(addition);
newPermutationsResult.Add(priorWithAddition);
}
}
return newPermutationsResult;
}
What you are asking for is called the Cartesian Product. Once you know what its called, there are several similar questions on Stack Overflow. They all seem to end up pointing to an answer which ended up written as a blog post:
http://blogs.msdn.com/b/ericlippert/archive/2010/06/28/computing-a-cartesian-product-with-linq.aspx
Non-recursive solution:
foreach (String s1 in array1) {
foreach (String s2 in array2) {
foreach (String s3 in array3) {
String result = s1 + " " + s2 + " " + s3;
//do something with the result
}
}
}
Recursive solution:
private ArrayList<String> permute(ArrayList<ArrayList<String>> ar, int startIndex) {
if (ar.Count == 1) {
foreach(String s in ar.Value(0)) {
ar.Value(0) = "val" + startIndex + "=" + ar.Value(0);
return ar.Value(0);
}
ArrayList<String> ret = new ArrayList<String>();
ArrayList<String> tmp1 ar.Value(0);
ar.remove(0);
ArrayList<String> tmp2 = permute(ar, startIndex+1);
foreach (String s in tmp1) {
foreach (String s2 in tmp2) {
ret.Add("val" + startIndex + "=" + s + " " + s2);
}
}
return ret;
}
Here is a generic recursive function that I wrote (and an overload that may be convenient to call):
Public Shared Function GetCombinationsFromIEnumerables(ByRef chain() As Object, ByRef IEnumerables As IEnumerable(Of IEnumerable(Of Object))) As List(Of Object())
Dim Combinations As New List(Of Object())
If IEnumerables.Any Then
For Each v In IEnumerables.First
Combinations.AddRange(GetCombinationsFromIEnumerables(chain.Concat(New Object() {v}).ToArray, IEnumerables.Skip(1)).ToArray)
Next
Else
Combinations.Add(chain)
End If
Return Combinations
End Function
Public Shared Function GetCombinationsFromIEnumerables(ByVal ParamArray IEnumerables() As IEnumerable(Of Object)) As List(Of Object())
Return GetCombinationsFromIEnumerables(chain:=New Object() {}, IEnumerables:=IEnumerables.AsEnumerable)
End Function
And the equivalent in C#:
public static List<object[]> GetCombinationsFromIEnumerables(ref object[] chain, ref IEnumerable<IEnumerable<object>> IEnumerables)
{
List<object[]> Combinations = new List<object[]>();
if (IEnumerables.Any) {
foreach ( v in IEnumerables.First) {
Combinations.AddRange(GetCombinationsFromIEnumerables(chain.Concat(new object[] { v }).ToArray, IEnumerables.Skip(1)).ToArray);
}
} else {
Combinations.Add(chain);
}
return Combinations;
}
public static List<object[]> GetCombinationsFromIEnumerables(params IEnumerable<object>[] IEnumerables)
{
return GetCombinationsFromIEnumerables(chain = new object[], IEnumerables = IEnumerables.AsEnumerable);
}
Easy to use:
Dim list1 = New String() {"hello", "bonjour", "hallo", "hola"}
Dim list2 = New String() {"Erwin", "Larry", "Bill"}
Dim list3 = New String() {"!", ".."}
Dim result = MyLib.GetCombinationsFromIEnumerables(list1, list2, list3)
For Each r In result
Debug.Print(String.Join(" "c, r))
Next
or in C#:
object list1 = new string[] {"hello","bonjour","hallo","hola"};
object list2 = new string[] {"Erwin", "Larry", "Bill"};
object list3 = new string[] {"!",".."};
object result = MyLib.GetCombinationsFromIEnumerables(list1, list2, list3);
foreach (r in result) {
Debug.Print(string.Join(' ', r));
}
Here is a version which uses very little code, and is entirely declarative
public static IEnumerable<IEnumerable<T>> GetPermutations<T>(IEnumerable<T> collection) where T : IComparable
{
if (!collection.Any())
{
return new List<IEnumerable<T>>() {Enumerable.Empty<T>() };
}
var sequence = collection.OrderBy(s => s).ToArray();
return sequence.SelectMany(s => GetPermutations(sequence.Where(s2 => !s2.Equals(s))).Select(sq => (new T[] {s}).Concat(sq)));
}
class Program
{
static void Main(string[] args)
{
var listofInts = new List<List<int>>(3);
listofInts.Add(new List<int>{1, 2, 3});
listofInts.Add(new List<int> { 4,5,6 });
listofInts.Add(new List<int> { 7,8,9,10 });
var temp = CrossJoinLists(listofInts);
foreach (var l in temp)
{
foreach (var i in l)
Console.Write(i + ",");
Console.WriteLine();
}
}
private static IEnumerable<List<T>> CrossJoinLists<T>(IEnumerable<List<T>> listofObjects)
{
var result = from obj in listofObjects.First()
select new List<T> {obj};
for (var i = 1; i < listofObjects.Count(); i++)
{
var iLocal = i;
result = from obj in result
from obj2 in listofObjects.ElementAt(iLocal)
select new List<T>(obj){ obj2 };
}
return result;
}
}
Here's a non-recursive, non-Linq solution. I can't help feeling like I could have less looping and calculate the positions with division and modulo, but can't quite wrap my head around that.
static void Main(string[] args)
{
//build test list
List<string[]> myList = new List<string[]>();
myList.Add(new string[0]);
myList.Add(new string[0]);
myList.Add(new string[0]);
myList[0] = new string[] { "1", "2", "3"};
myList[1] = new string[] { "4", "5" };
myList[2] = new string[] { "7", "8", "9" };
object[][] xProds = GetProducts(myList.ToArray());
foreach(object[] os in xProds)
{
foreach(object o in os)
{
Console.Write(o.ToString() + " ");
}
Console.WriteLine();
}
Console.ReadKey();
}
static object[][] GetProducts(object[][] jaggedArray){
int numLists = jaggedArray.Length;
int nProducts = 1;
foreach (object[] oArray in jaggedArray)
{
nProducts *= oArray.Length;
}
object[][] productAry = new object[nProducts][];//holds the results
int[] listIdxArray = new int[numLists];
listIdxArray.Initialize();
int listPtr = 0;//point to current list
for(int rowcounter = 0; rowcounter < nProducts; rowcounter++)
{
//create a result row
object[] prodRow = new object[numLists];
//get values for each column
for(int i=0;i<numLists;i++)
{
prodRow[i] = jaggedArray[i][listIdxArray[i]];
}
productAry[rowcounter] = prodRow;
//move the list pointer
//possible states
// 1) in a list, has room to move down
// 2) at bottom of list, can move to next list
// 3) at bottom of list, no more lists left
//in a list, can move down
if (listIdxArray[listPtr] < (jaggedArray[listPtr].Length - 1))
{
listIdxArray[listPtr]++;
}
else
{
//can move to next column?
//move the pointer over until we find a list, or run out of room
while (listPtr < numLists && listIdxArray[listPtr] >= (jaggedArray[listPtr].Length - 1))
{
listPtr++;
}
if (listPtr < listIdxArray.Length && listIdxArray[listPtr] < (jaggedArray[listPtr].Length - 1))
{
//zero out the previous stuff
for (int k = 0; k < listPtr; k++)
{
listIdxArray[k] = 0;
}
listIdxArray[listPtr]++;
listPtr = 0;
}
}
}
return productAry;
}
One of the problems I encountred when I was doing this for a very large amount of codes was that with the example brian was given I actually run out of memory. To solve this I used following code.
static void foo(string s, List<Array> x, int a)
{
if (a == x.Count)
{
// output here
Console.WriteLine(s);
}
else
{
foreach (object y in x[a])
{
foo(s + y.ToString(), x, a + 1);
}
}
}
static void Main(string[] args)
{
List<Array> a = new List<Array>();
a.Add(new string[0]);
a.Add(new string[0]);
a.Add(new string[0]);
a[0] = new string[] { "T", "Z" };
a[1] = new string[] { "N", "Z" };
a[2] = new string[] { "3", "2", "Z" };
foo("", a, 0);
Console.Read();
}
private static void GetP(List<List<string>> conditions, List<List<string>> combinations, List<string> conditionCombo, List<string> previousT, int selectCnt)
{
for (int i = 0; i < conditions.Count(); i++)
{
List<string> oneField = conditions[i];
for (int k = 0; k < oneField.Count(); k++)
{
List<string> t = new List<string>(conditionCombo);
t.AddRange(previousT);
t.Add(oneField[k]);
if (selectCnt == t.Count )
{
combinations.Add(t);
continue;
}
GetP(conditions.GetRange(i + 1, conditions.Count - 1 - i), combinations, conditionCombo, t, selectCnt);
}
}
}
List<List<string>> a = new List<List<string>>();
a.Add(new List<string> { "1", "5", "3", "9" });
a.Add(new List<string> { "2", "3" });
a.Add(new List<string> { "93" });
List<List<string>> result = new List<List<string>>();
GetP(a, result, new List<string>(), new List<string>(), a.Count);
Another recursive function.

Categories