C# Finding "connected" permutations - c#

I'm working on a dictionary table and required to find out all possible combination of characters in a word. Thanks to https://codereview.stackexchange.com/questions/28248/implement-a-function-that-prints-all-possible-combinations-of-the-characters-in , I got below working so far:
public List<string> findAllOccurance(string str)
{
var results = from e in Range(0, BigInteger.Pow(2, str.Length))
let p =
from b in Enumerable.Range(1, str.Length)
select (e & BigInteger.Pow(2, b - 1)) == 0 ? (char?)null : str[b - 1]
select string.Join(string.Empty, p);
return results.ToList();
}
public IEnumerable<BigInteger> Range(BigInteger start, BigInteger count)
{
while (count-- > 0)
{
yield return start++;
}
}
Passing "abc" to above function would returns:
a
b
ab
c
ac
bc
abc
The problem is I actually would like to find out only the "connected" permutations in "original order", for example "abc" should return only
a
b
c
ab
bc
abc
Does anyone have any idea what should I change to achieve above?

By "connected" permutations - you are effectively looking for all substrings from length 1 up to the full length of the string. This can be very easily done with two for loops. The duplicates can be removed by using Linq's Distinct() method.
public List<string> findAllOccurance(string str)
{
List<string> result = new List<string>();
for (int i = 1; i <= str.Length; i++)
{
for (int j=0; j <= str.Length-i; j++)
result.Add(str.Substring(j,i));
}
return result.Distinct().ToList();
}
NOTE - if you really do want to return an empty string - you can either modify the outer loop to start from 0 or simply manually add it after creating the list instance. Modifying the loop will result in str.Length empty strings being added & more work for Distinct() when you know you will only ever always want 1 empty string returned.
List<string> result = new List<string>();
result.Add(String.Empty);
for (int i = 1; i <= str.Length; i++)
.....

I don't know if I understand "connected" right... Maybe you could simply check if a potential result is a part of the original string... Something like this:
public List<string> findAllOccurance(string str)
{
var results = from e in Range(0, BigInteger.Pow(2, str.Length))
let p =
from b in Enumerable.Range(1, str.Length)
select (e & BigInteger.Pow(2, b - 1)) == 0 ? (char?)null : str[b - 1]
let p2 = string.Join(string.Empty, p)
where str.Contains(p2)
select p2;
return results.ToList();
}
public IEnumerable<BigInteger> Range(BigInteger start, BigInteger count)
{
while (count-- > 0)
{
yield return start++;
}
}

For your code, you are performing bitwise operation in order to find all possible subsets. For the case abc your string length is 3. So possible subsets = 2 ^ 3 = 8. Writing them down and matching the rightmost bit with the leftmost index:
Possible cases:
0 0 0 // gives nothing
0 0 1 // gives 'a' (valid)
0 1 0 // gives 'b' (valid)
0 1 1 // gives 'ab' (valid)
1 0 0 // gives 'c' (valid)
1 0 1 // gives 'ac' (invalid as there is a 0 inbetween and not connected)
1 1 0 // gives 'bc' (valid)
1 1 1 // gives 'abc' (valid)
The above is what I understand for what you count as connected. You can easily perform a check to do this with two loops:
int max_size = BigInteger.Pow(2, str.Length);
int str_size = str.Length;
for(int i = 0; i < max_size; ++i)
{
string ans = "";
for(j = 0; j < str_size; ++j)
{
// We check if the jth bit is set, we print the jth element from the string.
if(i & (1 << j))
ans += str[j];
}
else {
if(ans.Length > 0){
// this means we have already added a character and then the next consecutive bit is '0'
ans = "";
break;
}
}
if(ans != ""){
Console.Writeline(ans); // we print the set. you can control this anyway you want.
}
}
}

Related

Algorithm to get which values make sum of a given number from array

I don't know to search or google it so I ask it here.
I have an array of integers with fixed size and exactly with this logic.
sample [1,2,4,8,16,32]
Now I am given a number for example 26. And I shall find the numbers whose sum will make this number, in this case is [2,8,16]
for a number of 20 it will be [4,16]
for 40 it is [8,32]
and for 63 it is all of these numbers [1,2,4,8,16,32]
What is the proper algorithm for that?
I know strictly that there is always this continuation that the number is double of the previous value.
as well as only the numbers from the given array will sum up to the given number and each number will be used only for once or none
If it will be in C# method that takes array of ints and an int value and returns the array of ints that contains the ints that sum up this number from the given array will be preferred.
Thank you
As you can see, the number are base-2, which means you can easily use shift.
You could try this:
private IEnumerable<int> FindBits(int value)
{
// check for bits.
for (int i = 0; i < 32; i++)
{
// shift 1 by i
var bitVal = 1 << i; // you could use (int)Math.Pow(2, i); instead
// check if the value contains that bit.
if ((value & bitVal) == bitVal)
// yep, it did.
yield return bitVal;
}
}
This method will check what bits are set and return them as an ienumerable. (which can be converted to an array of list)
Usage:
// find the bits.
var res = FindBits(40).ToArray();
// format it using the string.join
var str = $"[{string.Join(",", res)}]";
// present the results
Console.WriteLine(str);
Results in [8,32]
Extra info:
counter
00000001 = 1 = 1 << 0
00000010 = 2 = 1 << 1
00000100 = 4 = 1 << 2
00001000 = 8 = 1 << 3
00010000 = 16 = 1 << 4
00100000 = 32 = 1 << 5
01000000 = 64 = 1 << 6
10000000 = 128 = 1 << 7
Instead of writing all combinations you make a for loop which does the counter.
Some extra non-sense:
If you like lambda's, you could replace the FindBits with this:
private Func<int, IEnumerable<int>> FindBits = (int value) => Enumerable
.Range(0, 31)
.Select(i => 2 << i).Where(i => (value & i) == i);
But it's better to keep it simpel/readable.
First you should notice that
( 1 2 4 8 16 ... ) = (2^0 2^1 2^2 2^3 2^4 ... )
And that this is the same as finding a binary encoding for a decimal number. What you are looking for is an algorithm to transform a decimal or base 10 number to a binary or base 2 number.
The algorithm is pretty simple:
public List<int> dec_to_bin(int num)
{
List<int> return_list = new List<int>();
int index = 0;
int remainder = num;
int bit = 0;
while (remainder > 0)
{
bit = remainder % 2;
if (bit == 1 )
{
return_list.Add((int)Math.Pow(2, index));
}
remainder = remainder / 2;
index = index + 1;
}
return return_list;
}
There is a better way however that just uses the underlying encoding of the number which is already binary.
public List<int> dec_to_bin(int num)
{
List<int> return_list = new List<int>();
int value = 1;
while( value < num )
{
if( (value & num) == value )
{
return_list.Add(value);
}
value = value * 2;
}
return return_list;
}
Another way to state your requirement is "What are the unique powers of 2 that sum to a given integer?" Since computers work with powers of 2 natively, there are built-in goodies in most languages to do this very succinctly.
As a bonus, you can use existing .Net types and methods to eliminate the need to write your own loops.
Here's one approach:
IEnumerable<int> GetCompositePowersOf2(int input) =>
//convert to enumerable of bools, one for each bit in the
//input value (true=1, false=0)
new BitArray(new[] { input }).Cast<bool>()
// get power of 2 corresponding to the position in the enumerable
// for each true value, gets 0 for false values.
.Select((isOne, pos) => isOne ? (1 << pos) : 0)
//filter out the 0 values
.Where(pow => pow > 0);
I don't quite get the " takes array of ints " part, since this creation of sums only works with numbers that are the power of 2.
private int[] count (int num)
{
int factor = 0;
List<int> facts = new List<int>();
while (num > 0)
{
int counter = 0;
int div = num;
int remainder = 0;
while (remainder == 0)
{
remainder = div % 2;
div = div / 2;
counter++;
}
factor = 1;
for (int i = 1; i < counter; i++)
factor *= 2;
num = num - factor;
facts.Add(factor);
}
return (facts.ToArray());
}

Where is the flaw in my algorithm to get the largest palindrome is a string representation of a number?

I'm trying to get the largest palindrome that can be formed by k replacements of digits in the string number.
e.g.
number="3943",k=1 --> "3993"
For that exact test case I am getting "393" and for some test cases I am getting an error like
Unhandled Exception: System.InvalidOperationException: Sequence
contains no elements at System.Linq.Enumerable.Last[TSource]
(IEnumerable`1 source) <0x414ec920 + 0x001ab> in :0
at Solution.LargestPalindrome (System.String numstr, Int32 k)
[0x00197] in solution.cs:74 at
Solution+c__AnonStorey0.<>m__0 (System.String str)
[0x00009] in solution.cs:61
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
class Solution
{
static bool IsPalindrome(string s)
{
// returns true or false depending on whether the string
// s is a palindrome
// e.g. "abba" --> true, "acba" --> false
for(int i = 0, j = s.Length - 1; i < j; ++i, --j)
{
if(s[i] != s[j])
return false;
}
return true;
}
static string Replace(string s, int i, char c)
{
// returns a copy of s with the character at index i
// replaced by character c
// e.g. "george",2,"x" --> "gexrge"
string part1 = s.Length > 0 ? s.Substring(0, i) : string.Empty;
string part2 = i < (s.Length - 1) ? c.ToString() : string.Empty;
string part3 = (i + 1) < (s.Length - 1) ? s.Substring(i + 1, s.Length - i - 1) : string.Empty;
return part1 + part2 + part3;
}
static string LargestPalindrome(string numstr, int k)
{
// numstr: string representation of number
// k: maximum number of digit replacements allowed
// if no digit replacements allowed, return same string
if(k == 0)
return numstr;
// digrange will be {'0', '1', ..., '9'}
List<char> digrange = new List<char>();
for(char c = '0'; c <= '9'; ++c)
digrange.Add(c);
// possibilities will be all possibilities of replacing one digit from numstr
// e.g. numstr="02" --> possibilities={"12","22","32",...,"92","00","01","03","09"}
List<string> possibilities = new List<string>();
for(int i = 0; i < numstr.Length; ++i)
{
foreach(char dig in digrange.Where(d => d != numstr[i]))
{
possibilities.Add(Replace(numstr,i,dig));
}
}
// if k = 1, get all the strings in cumulativePossiblities that are palindromes;
// else, transform each into the largest palindrome formed by k - 1 character
// replacements of itself
var cumulativePossibilities = k == 1
? possibilities.Where(str => IsPalindrome(str))
: possibilities.Select(str => LargestPalindrome(str, k - 1)).Where(str => IsPalindrome(str));
// sort cumulativePossibilities in ascending order of the integer representation
// of the strings
cumulativePossibilities.ToList().Sort((s1,s2) => {
Int64 i1 = Int64.Parse(s1),
i2 = Int64.Parse(s2);
return (i1 > i2) ? 1 : ((i1 == i2) ? 0 : -1);
});
// get the last element of the now-sorted cumulativePossibilities,
// which will be the largest number represented by the possible strings
// or will be null if there are none
string largest = cumulativePossibilities.Last();
// return the largest or "-1" if there were none
return largest != null ? largest : "-1";
}
static void Main(String[] args)
{
string[] tokens_n = Console.ReadLine().Split(' ');
int k = Convert.ToInt32(tokens_n[1]);
string number = Console.ReadLine();
// use brute force algorithm to find largest palindrome of the string
// representation of the number after k replacements of characters
Console.WriteLine(LargestPalindrome(number,k));
}
}
Not very efficient method, but simple to implement; the key feature is using PalindromeSubstitutions (counting how many characters' substitutions prevents string from being palindrome) instead of IsPalindrome (just a fact if string is palindrome or not)
// How many characters should be substituted in order to
// turn the string into palindrom
private static int PalindromeSubstitutions(string value) {
if (string.IsNullOrEmpty(value))
return 0;
int result = 0;
for (int i = 0; i < value.Length / 2; ++i)
if (value[i] != value[value.Length - 1 - i])
result += 1;
return result;
}
// Let's test all substrings of size Length, Length - 1, ... , 2, 1
// until we find substring with required tolerance
private static string BestPalindromeSubstitutions(string value, int tolerance) {
for (int size = value.Length; size >= 1; --size)
for (int start = 0; start <= value.Length - size; ++start)
if (PalindromeSubstitutions(value.Substring(start, size)) <= tolerance)
return value.Substring(start, size);
return "";
}
private static string SubstituteToPalindrome(string value) {
if (string.IsNullOrEmpty(value))
return value;
StringBuilder sb = new StringBuilder(value);
for (int i = 0; i < value.Length / 2; ++i)
sb[value.Length - 1 - i] = sb[i];
return sb.ToString();
}
Test:
string input = "73943";
string best = BestPalindromeSubstitutions(input, 1);
string report =
string.Format("Best palindrome {0} -> {1}", best, SubstituteToPalindrome(best));
Output
Best palindrome 3943 -> 3993
The problem is a quite simple example of greedy algorithm. let's first count how many permutations are required (at minimum) to transform the number into palindrome.
int req = 0;
for(int i = 0; i <= (s.length()-1)/2; i++){
if (s[i] != s[s.length()-1-i] && i != s.length()-1-i) req++;
}
Now once it is done, let's go through digits from left to right once again: i goes through 0 to (s.length()-1)/2 inclusive. Consider the following cases ( here i is not the middle letter, that case we consider separately) :
s[i] == s[s.length()-i-1], it wasn't counted in req, so if k >= req + 2 and s[i] != '9', we change both letters to '9', and reduce k by 2, req remains unchanged. But note that we guaranteed that there are enough operations left to make sure that number can be turned into palindrome (if it was initially possible)
s[i] != s[s.length()-i-1] - now if k == req or one of the letters is '9', then do the following: s[i]=s[s.length()-i-1]=max({s[i], s[s.length()-i-1]}). Reduce both k and req by 1.
Now if k > req and both letters are not '9', we change them both to 9. k -= 2, req -= 1.
Now if i = s.length()-i-1 and k > 0, change this letter s[i] to '9'.
The result u get at the end is what u are looking for.
Total complexity is O(n).

Reassigning a value to a character array not working

I am currently having issues reassigning a value to a character array. Below is my code (unfinished solution to find the next smallest palindrome):
public int nextSmallestPalindrome(int number)
{
string numberString = number.ToString();
// Case 1: Palindrome is all 9s
for (int i = 0; i < numberString.Length; i++)
{
if (numberString[i] != '9')
{
break;
}
int result = number + 2;
return result;
}
// Case 2: Is a palindrome
int high = numberString.Length - 1;
int low = 0;
bool isPalindrome = true;
for (low = 0; low <= high; low++, high--)
{
if (numberString[low] != numberString[high])
{
isPalindrome = false;
break;
}
}
char[] array = numberString.ToCharArray();
if (isPalindrome == true)
{
// While the middle character is 9
while (numberString[high] == '9' || numberString[low] == '9')
{
array[high] = '0';
array[low] = '0';
high++;
low--;
}
int replacedvalue1 = (int)Char.GetNumericValue(numberString[high]) + 1;
int replacedvalue2 = (int)Char.GetNumericValue(numberString[low]) + 1;
StringBuilder result = new StringBuilder(new string(array));
if (high == low)
{
result[high] = (char)replacedvalue1;
}
else
{
Console.WriteLine(result.ToString());
result[high] = (char)replacedvalue1;
Console.WriteLine(result.ToString());
result[low] = (char)replacedvalue2;
}
return Int32.Parse(result.ToString());
}
else return -1;
}
Main class runs:
Console.WriteLine(nextSmallestPalindrome(1001));
This returns 1001, then 101 and then gives a formatexception at the return Int32.Parse(result.ToString()); statement.
I am very confused, as I believe "result" should be 1101 after I assign result[high] = (char)replacedvalue1;. Printing replacedvalue1 gives me "1" as expected. However, debugging it line by line shows that "1001" turns into "1 1" at the end, signifying strange characters.
What could be going wrong?
Thanks
Characters and numbers aren't the same thing. I find it easiest to keep an ASCII chart open when doing this sort of thing.
If you look at one of those charts, you'll see that the character 0 actually has a decimal value of 48.
char c = (char)48; // Equals the character '0'
The reverse is also true:
char c = '0';
int i = (int)c; // Equals the number 48
You managed to keep chars and ints separate for the most part, but at the end you got them mixed up:
// Char.GetNumericValue('0') will return the number 0
// so now replacedvalue1 will equal 1
int replacedvalue1 = (int)Char.GetNumericValue(numberString[high]) + 1;
// You are casting the number 1 to a character, which according to the
// ASCII chart is the (unprintable) character SOH (start of heading)
result[high] = (char)replacedvalue1;
FYI you don't actually need to cast a char back-and-forth in order to perform operations on it. char c = 'a'; c++; is valid, and will equal the next character on the table ('b'). Similarly you can increment numeric characters:
char c = '0'; c++; // c now equals '1'
Edit: The easiest way to turn an integer 1 into the character '1' is to "add" the integer to the character '0':
result[high] = (char)('0' + replacedvalue1);
Of course there are much easier ways to accomplish what you are trying to do, but these techniques (converting and adding chars and ints) are good tools to know.
You do not have write that much code to do it.
Here is your IsPalindrome method;
private static bool IsPalindrome(int n)
{
string ns = n.ToString(CultureInfo.InvariantCulture);
var reversed = string.Join("", ns.Reverse());
return (ns == reversed);
}
private static int FindTheNextSmallestPalindrome(int x)
{
for (int i = x; i < 2147483647; i++)
{
if (IsPalindrome(i))
{
return i;
}
}
throw new Exception("Number must be less than 2147483647");
}
This is how you call it. You do not need an array to call it. You can just enter any number which is less than 2147483647(max value of int) and get the next palindrome value.
var mynumbers = new[] {10, 101, 120, 110, 1001};
foreach (var mynumber in mynumbers)
{
Console.WriteLine(FindTheNextPalindrome(mynumber));
}

String Combinations With Character Replacement

I am trying to work through a scenario I haven't seen before and am struggling to come up with an algorithm to implement this properly. Part of my problem is a hazy recollection of the proper terminology. I believe what I am needing is a variation of the standard "combination" problem, but I could well be off there.
The Scenario
Given an example string "100" (let's call it x), produce all combinations of x that swap out one of those 0 (zero) characters for a o (lower-case o). So, for the simple example of "100", I would expect this output:
"100"
"10o"
"1o0"
"1oo"
This would need to support varying length strings with varying numbers of 0 characters, but assume there would never be more than 5 instances of 0.
I have this very simple algorithm that works for my sample of "100" but falls apart for anything longer/more complicated:
public IEnumerable<string> Combinations(string input)
{
char[] buffer = new char[input.Length];
for(int i = 0; i != buffer.Length; ++i)
{
buffer[i] = input[i];
}
//return the original input
yield return new string(buffer);
//look for 0's and replace them
for(int i = 0; i != buffer.Length; ++i)
{
if (input[i] == '0')
{
buffer[i] = 'o';
yield return new string(buffer);
buffer[i] = '0';
}
}
//handle the replace-all scenario
yield return input.Replace("0", "o");
}
I have a nagging feeling that recursion could be my friend here, but I am struggling to figure out how to incorporate the conditional logic I need here.
Your guess was correct; recursion is your friend for this challenge. Here is a simple solution:
public static IEnumerable<string> Combinations(string input)
{
int firstZero = input.IndexOf('0'); // Get index of first '0'
if (firstZero == -1) // Base case: no further combinations
return new string[] { input };
string prefix = input.Substring(0, firstZero); // Substring preceding '0'
string suffix = input.Substring(firstZero + 1); // Substring succeeding '0'
// e.g. Suppose input was "fr0d00"
// Prefix is "fr"; suffix is "d00"
// Recursion: Generate all combinations of suffix
// e.g. "d00", "d0o", "do0", "doo"
var recursiveCombinations = Combinations(suffix);
// Return sequence in which each string is a concatenation of the
// prefix, either '0' or 'o', and one of the recursively-found suffixes
return
from chr in "0o" // char sequence equivalent to: new [] { '0', 'o' }
from recSuffix in recursiveCombinations
select prefix + chr + recSuffix;
}
This works for me:
public IEnumerable<string> Combinations(string input)
{
var head = input[0] == '0' //Do I have a `0`?
? new [] { "0", "o" } //If so output both `"0"` & `"o"`
: new [] { input[0].ToString() }; //Otherwise output the current character
var tails = input.Length > 1 //Is there any more string?
? Combinations(input.Substring(1)) //Yes, recursively compute
: new[] { "" }; //Otherwise, output empty string
//Now, join it up and return
return
from h in head
from t in tails
select h + t;
}
You don't need recursion here, you can enumerate your patterns and treat them as binary numbers. For example, if you have three zeros in your string, you get:
0 000 ....0..0....0...
1 001 ....0..0....o...
2 010 ....0..o....0...
3 011 ....0..o....o...
4 100 ....o..0....0...
5 101 ....o..0....o...
6 110 ....o..o....0...
7 111 ....o..o....o...
You can implement that with bitwise operators or by treating the chars that you want to replace like an odometer.
Below is an implementation in C. I'm not familiar with C# and from the other answers I see that C# already has suitable standard classes to implement what you want. (Although I'm surprised that so many peolpe propose recursion here.)
So this is more an explanation or illustration of my comment to the question than an implementation advice for your problem.
int binrep(char str[])
{
int zero[40]; // indices of zeros
int nzero = 0; // number of zeros in string
int ncombo = 1; // number of result strings
int i, j;
for (i = 0; str[i]; i++) {
if (str[i] == '0') {
zero[nzero++] = i;
ncombo <<= 1;
}
}
for (i = 0; i < ncombo; i++) {
for (j = 0; j < nzero; j++) {
str[zero[j]] = ((i >> j) & 1) ? 'o' : '0';
}
printf("%s\n", str); // should yield here
}
return ncombo;
}
Here's a solution using recursion, and your buffer array:
private static void Main(string[] args)
{
var a = Combinations("100");
var b = Combinations("10000");
}
public static IEnumerable<string> Combinations(string input)
{
var combinations = new List<string>();
combinations.Add(input);
for (int i = 0; i < input.Length; i++)
{
char[] buffer= input.ToArray();
if (buffer[i] == '0')
{
buffer[i] = 'o';
combinations.Add(new string(buffer));
combinations = combinations.Concat(Combinations(new string(buffer))).ToList();
}
}
return combinations.Distinct();
}
The method adds the raw input as the first result. After that, we replace in a loop the 0s we see as a o and call our method back with that new input, which will cover the case of multiple 0s.
Finally, we end up with a couple duplicates, so we use Distinct.
I know that the earlier answers are better. But I don't want my code to go to waste. :)
My approach for this combinatorics problem would be to take advantage of how binary numbers work. My algorithm would be as follows:
List<string> ZeroCombiner(string str)
{
// Get number of zeros.
var n = str.Count(c => c == '0');
var limit = (int)Math.Pow(2, n);
// Create strings of '0' and 'o' based on binary numbers from 0 to 2^n.
var binaryStrings = new List<string>();
for (int i = 0; i < limit; ++i )
{
binaryStrings.Add(Binary(i, n + 1));
}
// Replace each zero with respect to each binary string.
var result = new List<string>();
foreach (var binaryString in binaryStrings)
{
var zeroCounter = 0;
var combinedString = string.Empty;
for (int i = 0; i < str.Length; ++i )
{
if (str[i] == '0')
{
combinedString += binaryString[zeroCounter];
++zeroCounter;
}
else
combinedString += str[i];
}
result.Add(combinedString);
}
return result;
}
string Binary(int i, int n)
{
string result = string.Empty;
while (n != 0)
{
result = result + (i % 2 == 0 ? '0' : 'o');
i = i / 2;
--n;
}
return result;
}

How do you iterate through permutations in order of least to most non-zero elements?

I am trying to write a C# function that, given an argument like new int[] { 2, 3, 2 } which specifies the upper bound + 1 for each element, would return the following (via IEnumberable<int[]>):
0 0 0
0 0 1
0 1 0
0 2 0
1 0 0
0 1 1
0 2 1
1 0 1
1 1 0
1 2 0
1 1 1
1 2 1
Note that the order is important: all the permutations with 0 non-zero elements, followed by all those with 1 non-zero elements, etc. Within one of those groups the order doesn't matter.
I realize that these may not technically be permutations, but it's the closest term that I know of. Also I realize that one way would be to return all the permutations in some order and then sort them according to a function that counts how many non-zero elements there are, but I am hoping for something more elegant and efficient.
I wanted an answer that doesn't calculate everything first and then sort, while still only going through things the minimal amount of times. Here's what I've got. Note that externally modifying the int[] could screw up the results (alternately, could return a new int[]).
The first method tells the helper method how many 0's it wants in the output. The helper then calculates the results, stopping if it can't fill in enough 0's or if it runs through all the data.
static IEnumerable<int[]> Permutation(int[] bounds)
{
for(int num0s = bounds.Length; num0s >= 0; --num0s)
{
foreach(int[] ret in PermHelper(num0s, 0, bounds, new int[bounds.Length]))
yield return ret;
}
}
static IEnumerable<int[]> PermHelper(int num0s, int index, int[] bounds, int[] result)
{
//Last index.
if(index == bounds.Length - 1)
{
if(num0s > 0)
{
result[index] = 0;
yield return result;
}
else
{
for(int i = 1; i < bounds[index]; ++i)
{
result[index] = i;
yield return result;
}
}
}
//Others.
else
{
//still need more 0s.
if(num0s > 0)
{
result[index] = 0;
foreach(int[] perm in PermHelper(num0s - 1, index + 1, bounds, result))
yield return perm;
}
//Make sure there are enough 0s left if this one isn't a 0.
if(num0s < bounds.Length - index)
{
for(int i = 1; i < bounds[index]; ++i)
{
result[index] = i;
foreach(int[] perm in PermHelper(num0s, index + 1, bounds, result))
yield return perm;
}
}
}
}
I apologize if this code has syntax errors (not in a position to test) but hopefully you get the idea.
IEnumerable<int[]> Permutations(int[] upperBounds) {
int[] c = new int[upperBounds.Length] {};
while(true) {
int i = c.Length - 1;
while(i >= 0 && c[i] == upperBounds[i]) {
c[i] = 0;
i--;
}
if(i == -1) break;
c[i]++;
yield return (int[]) c.Clone();
}
}
It gets even better if you use a callback and keep the same array reference, but you asked for an IEnumerable. If not using Clone is possible, by all means, please use it - it will be much more efficient.

Categories