Appending '0' using concat does not seem to work - c#

I have a program that compares two integer value's length with this extension method
public static int NumDigits(this int n)
{
if (n < 0)
{
n = (n == int.MinValue) ? int.MaxValue : -n;
}
if (n < 10) return 1;
if (n < 100) return 2;
if (n < 1000) return 3;
if (n < 10000) return 4;
if (n < 100000) return 5;
if (n < 1000000) return 6;
if (n < 10000000) return 7;
if (n < 100000000) return 8;
return n < 1000000000 ? 9 : 10;
}
And it works perfectly. When I print the value of num1.numDigits(), the value returns 4 (it is worth '1111'. And my other integer: num2.numDigits() returns 2 (it is 11). This is great but when I actually compare them:
int[] rawNum2 = Arrays.DigitArr(num2);
if (num1.NumDigits() > num2.NumDigits())
{
int diff = num1.NumDigits() - num2.NumDigits();
for (int i = 1; i < diff; i++)
{
rawNum2.Append(0);
}
reversedNum2 = rawNum2.Reverse();
}
reversedNum2 is still '11' when it should be '0011'.
This is the class I compiled and used.
public static int[] Append(this int[] source, int value)
{
int[] newValue = source;
newValue = newValue.Concat(new[] { value }).ToArray();
return newValue;
}
public static int[] Reverse(this int[] array)
{
int[] arr = array;
for (int i = 0; i < arr.Length / 2; i++)
{
int tmp = arr[i];
arr[i] = arr[arr.Length - i - 1];
arr[arr.Length - i - 1] = tmp;
}
return arr;
}
public static int[] DigitArr(int n)
{
if (n == 0) return new int[1] { 0 };
var digits = new List<int>();
for (; n != 0; n /= 10)
digits.Add(n % 10);
var arr = digits.ToArray();
Array.Reverse(arr);
return arr;
}
Why is this happening?

You are discarding the return value of the Append method.
Change
rawNum2.Append(0);
to
rawNum2 = rawNum2.Append(0);
inside the for loop.

Your loop could be and should be simplified to:
rawNum2 = rawNum2.PadRight(num1.NumDigits(), '0')

To get the reversedNum2 as 0011 change your loop as below.
for (int i = 1; i <= diff; i++)
{
rawNum2=rawNum2.Append(0);
}
I made two changes changed the for loop to use i<=diff instead of i < diff
and assigning the return value from Append() method into the rawNum2.

Related

returns the smallest positive integer (greater than 0) that does not occur in Array

I have the following question:-
Write a function:
class Solution { public int solution(int[] A); }
that, given an array A of N integers, returns the smallest positive integer (greater than 0) that does not occur in A.
For example, given A = [1, 3, 6, 4, 1, 2], the function should return 5.
Given A = [1, 2, 3], the function should return 4.
Given A = [−1, −3], the function should return 1.
Write an efficient algorithm for the following assumptions:
N is an integer within the range [1..100,000];
each element of array A is an integer within the range [−1,000,000..1,000,000].
now i tried this code:-
using System;
// you can also use other imports, for example:
// using System.Collections.Generic;
// you can write to stdout for debugging purposes, e.g.
// Console.WriteLine("this is a debug message");
class Solution
{
public int solution(int[] A)
{
// write your code in C# 6.0 with .NET 4.5 (Mono)
int n = 1;
Array.Sort(A);
for (int i = 1; i <= 100000; i++)
{
for (int i2 = 0; i2 <= A.Length - 1; i2++)
{
if (A[i2] == i)
{
n = A[i2] + 1;
break;
}
}
}
return n;
}
}
where my code worked well for these test data:-
A = [1, 2, 3]
A = [−1, −3]
while failed for this one:-
A = [1, 3, 6, 4, 1, 2] where it return 7 instead of 5.
any advice why my code failed on the 3rd test?
Thanks
using System.Linq;
int smallestNumber = Enumerable.Range(1, 100000).Except(A).Min();
I would use following approach that uses a HashSet<int> to check if a given integer is missing:
public static int? SmallestMissing(int[] A, int rangeStart = 1, int rangeEnd = 100_000)
{
HashSet<int> hs = new HashSet<int>(A);
for (int i = rangeStart; i <= rangeEnd; i++)
if(!hs.Contains(i)) return i;
return null;
}
A HashSet is a collection if unique values and it's very efficient in lookup items(complexity is O(1)). So you get a very readable and efficient algorithm at the cost of some memory.
Maybe you could optimize it by providing another algorithm in case the array is very large, you don't want to risk an OutOfMemoryException:
public static int? SmallestMissing(int[] A, int rangeStart = 1, int rangeEnd = 100_000)
{
if(A.Length > 1_000_000)
{
Array.Sort(A);
for (int i = rangeStart; i <= rangeEnd; i++)
{
int index = Array.BinarySearch(A, i);
if(index < 0) return i;
}
return null;
}
HashSet<int> hs = new HashSet<int>(A);
for (int i = rangeStart; i <= rangeEnd; i++)
if(!hs.Contains(i)) return i;
return null;
}
If you're allowed to sort the array in-place, which means modifying the input parameter value, here's a simple linear probe for the missing value (on top of the sort of course).
Here's the pseudo-code:
Sort the array
Skip all negatives and 0's at the start
Loopify the following:
Expect 1, if not found at current location return 1
Skip all 1's
Expect 2, if not found at current location return 2
Skip all 2's
Expect 3, if not found at current location return 3
Skip all 3's
... and so on for 4, 5, 6, etc. until end of array
If we get here, return currently expected value which should've been at the end
Here's the code:
public static int FirstMissingValue(int[] input)
{
Array.Sort(input);
int index = 0;
// Skip negatives
while (index < input.Length && input[index] < 1)
index++;
int expected = 1;
while (index < input.Length)
{
if (input[index] > expected)
return expected;
// Skip number and all duplicates
while (index < input.Length && input[index] == expected)
index++;
expected++;
}
return expected;
}
Test-cases:
Console.WriteLine(FirstMissingValue(new[] { 1, 3, 6, 4, 1, 2 }));
Console.WriteLine(FirstMissingValue(new[] { 1, 2, 3 }));
Console.WriteLine(FirstMissingValue(new[] { -1, -3 }));
output:
5
4
1
Your alg won't work in case input array becomes like this: [1,2-1,1,3,5]. I did this based on your alg. Give it a try:
int[] a = new int[] { -1, -2};
IEnumerable<int> uniqueItems = a.Distinct<int>().Where(x => x > 0);
if (uniqueItems.Count() == 0)
{
Console.WriteLine("result: 1");
}
else
{
Array asList = uniqueItems.ToArray();
Array.Sort(asList);
for (int i = 1; i <= 100000; i++)
{
if ((int)asList.GetValue(i - 1) != i)
{
Console.WriteLine("result: " + i);
break;
}
}
}
you can try like this.
public static int solution(int[] A)
{
int smallest = -1;
Array.Sort(A);
if(A[0] > 1)
return 1;
for(int i = 0; i < A.Length; i++)
{
if(A.Length != i+1 && A[i] + 1 != A[i + 1] && A[i+1] > 0)
{
smallest = A[i]+1;
break;
}
else if(A[i] > 0 && A.Length == i+1)
{
smallest = A[i] + 1;
}
}
return smallest > 0 ? smallest:1;
}
Here's the approach that uses O(N) partitioning followed by an O(N) search. This approach does not use any additional storage, but it DOES change the contents of the array.
This code was converted from here. Also see this article.
I've added comments to try to explain how the second stage findSmallestMissing() works. I've not commented the partitioning method, since that's just a variant of a standard partition as might be used in a QuickSort algorithm.
static class Program
{
public static void Main()
{
Console.WriteLine(FindSmallestMissing(1, 3, 6, 4, 1, 2));
Console.WriteLine(FindSmallestMissing(1, 2, 3));
Console.WriteLine(FindSmallestMissing(-1, -3));
}
public static int FindSmallestMissing(params int[] array)
{
return findSmallestMissing(array, partition(array));
}
// Places all the values > 0 before any values <= 0,
// and returns the index of the first value <= 0.
// The values are unordered.
static int partition(int[] arr)
{
void swap(int x, int y)
{
var temp = arr[x];
arr[x] = arr[y];
arr[y] = temp;
}
int pIndex = 0; // Index of pivot.
for (int i = 0; i < arr.Length; i++)
{
if (arr[i] > 0) // pivot is 0, hence "> 0"
swap(i, pIndex++);
}
return pIndex;
}
// This is the clever bit.
// We will use the +ve values in the array as flags to indicate that the number equal to that index is
// present in the array, by making the value negative if it is found in the array.
// This way we can store both the original number AND whether or not the number equal to that index is present
// in a single value.
//
// Given n numbers that are all > 0, find the smallest missing number as follows:
//
// For each array index i in (0..n):
// val = |arr[i]| - 1; // Subtract 1 so val will be between 0 and max +ve value in original array.
// if (val is in range) // If val beyond the end of the array we can ignore it
// and arr[val] is non-negative // If already negative, no need to make it negative.
// make arr[val] negative
//
// After that stage, we just need to find the first positive number in the array, which indicates that
// the number equal to that index + 1 is missing.
// n = number of values at the start of the array that are > 0
static int findSmallestMissing(int[] arr, int n)
{
for (int i = 0; i < n; i++)
{
int val = Math.Abs(arr[i]) - 1;
if (val < n && arr[val] >= 0)
arr[val] = -arr[val];
}
for (int i = 0; i < n; i++)
{
if (arr[i] > 0) // Missing number found.
return i + 1;
}
return n + 1; // No missing number found.
}
}
class Program
{
static void Main(string[] args)
{
int [] A = new int[] {1, 2, 3};
int n = 0;
bool found = false;
Array.Sort(A);
for (int i = 1; i <= 100000; i++) {
for (int x = 0; x <= A.Length - 1; x++) {
int next = (x + 1) < A.Length ? (x + 1): x;
if (A[x] > 0 && (A[next] - A[x]) > 0) {
n = A[x] + 1;
found = true;
break;
}
}
if(found) {
break;
}
}
Console.WriteLine("Smallest number: " + n);
}
}
int smallestNumber=Enumerable.Range(1,(int.Parse(A.Length.ToString())+1)).Except(A).Min();
Array.Sort(A);
for (int number = 1; number <= 100000; number++)
{
for (int num = number; i2 <= A.Length - 1; num++)
{
if (A[num] == number)
{
smallestNumber = A[num] + 1;
break;
}
}
}
return smallestNumber;
}
The easiest one :)
class Solution
{
public int solution(int[] array)
{
int[] onlyPositiveArray = array.Where(a => a > 0).OrderBy(a => a).Distinct().ToArray();
int smallestNumber = 1;
foreach (var number in onlyPositiveArray)
{
if (smallestNumber != number)
{
break;
}
smallestNumber ++;
}
if (!onlyPositiveArray.Contains(smallestNumber ))
{
return smallestNumber;
}
else
{
return smallestNumber + 1;
}
}
}
PHP Solution:
function solution($A) {
// write your code in PHP7.0
// sort array
sort($A);
// get the first
$smallest = $A[0];
// write while
while( in_array(($smallest),$A) || (($smallest) < 1 ) )
{
$smallest++;
}
return $smallest;
}
My solution, also if someone could test how performant it is?
public int solution(int[] N) {
if (N.Length == 0)
return 1;
else if (N.Length == 1)
return N[0] >= 0 ? N[0] + 1 : 1;
Array.Sort(N);
int min = Array.Find(N, IsUnderZero);
if (min ==
default)
return 1;
HashSet < int > hashSet = new HashSet < int > (N);
int max = N[N.Length - 1];
for (int i = min + 1; i <= max + 1; i++) {
if (!hashSet.Contains(i) && i > 0)
return i;
}
return max + 1;
bool IsUnderZero(int i) => i <= 0;
}
Try the below:
public static int MinIntegerGreaterThanZeroInArray(int[] A)
{
int minInt;
if (A.Length > 0)
{
Array.Sort(A);
for (minInt = 1; minInt <= A.Length; minInt++)
{
int index = Array.BinarySearch(A, minInt);
if (index < 0) return minInt;
}
return minInt;
}
//Array is empty.
throw new InvalidOperationException();
}
public static int Smallest(int[] A)
{
int maxPositiveInt = 1;
HashSet<int> NumDic = new HashSet<int>();
for (int i = 0; i < A.Length; i++)
{
if (A[i] <= 0)
{
continue;
}
if (!NumDic.Contains(A[i]))
{
NumDic.Add(A[i]);
}
maxPositiveInt = Math.Max(A[i], maxPositiveInt);
}
//All numbers are negative
if (NumDic.Count == 0)
{
return 1;
}
int smallestinteger = 1;
for (int i = 0; i < A.Length; i++)
{
if (A[i] <= 0)
{
continue;
}
if (!NumDic.Contains(smallestinteger))
{
return smallestinteger;
}
else
{
smallestinteger++;
}
}
return maxPositiveInt + 1;
}
static void Main(string[] args)
{
Console.WriteLine(solution(new int[]{1, 3, 6, 4, 1, 2}));
}
public static int solution(int[] A)
{
Array.Sort(A);
int smallest = A[0];
while (A.Contains(smallest+1)|| (smallest+1)<1)
{
smallest++;
}
return smallest +1;
}

ArrayIndexOutOfBounds exception in hackerrank Cut the sticks

I am trying to implement a problem in Hackerrank Cut the sticks. Problem can be found here
my code is this
static int[] cutTheSticks(int[] arr)
{
int n = arr.Length, k = 0;
int[] result = new int[n];
Array.Sort(arr);
Array.Reverse(arr);
while(arr.Length != 0)
{
result[k] = arr.Length;
k++;
for(int i = 0; i < n; ++i)
{
arr[i] -= arr[arr.Length - 1];
}
}
return result;
}
it shows error as-
System.IndexOutOfRangeException: Index was outside the bounds of the array.
at Solution.cutTheSticks (System.Int32[] arr) [0x00020] in solution.cs:24
line 24 is:
result[k] = arr.Length;
How to remove this?
There are several problems with your code. To name a few:
You are giving the result array a fixed size (int[] result=new int[n];), but it's size depends entirely on how many duplicate values are contained in the list.
You are supposed to remove from the array the smallest value(s) in each iteration. However you are just modifying the values (arr[i] -= arr[arr.Length - 1];), not removing them, so the array length will remain the same, and thus while (arr.Length != 0) will always be true, creating an endless loop. This causes k++ to keep incrementing until it reaches a value greater than the array length, which then results in the exception you are getting.
Since you are supposed to change the size of the input array, I suggest using List<int> instead, here's an example:
List<int> output = new List<int>();
List<int> input = new List<int>(arr);
while (input.Count > 0)
{
output.Add(input.Count);
int min = input.Min();
input.RemoveAll(x => x == min);
input.ForEach(x => x -= min);
}
return output.ToArray();
It is necessary to add condition k < n before assigning value to avoid IndexOutOfRangeException exception. In addition, there is a strong need a condition to avoid infinite while loop :
static int[] cutTheSticks(int[] arr) {
int n = arr.Length,
k = 0;
int[] result = new int[n];
Array.Sort(arr);
Array.Reverse(arr);
while (arr.Length != 0)
{
if (k < n)
result[k] = arr.Length;
else
break;
k++;
for (int i = 0; i < n; ++i)
{
arr[i] -= arr[arr.Length - 1];
}
}
return result;
}
UPDATE:
It is possible to pop out one element after every iteration like this:
static int[] cutTheSticks(int[] arr)
{
int n = arr.Length,
k = 0;
int[] result = new int[n];
var arrToBeRemoved = arr.ToList();
Array.Sort(arr);
Array.Reverse(arr);
while (arr.Length != 0)
{
if (k < n)
result[k] = arr.Length;
else
break;
if (k < arrToBeRemoved.Count)
arrToBeRemoved.RemoveAt(k);
arr = arrToBeRemoved.ToArray();
k++;
for (int i = 0; i < arr.Length; ++i)
{
arr[i] -= arr[arr.Length - 1];
}
}
return result;
}
I would do it that way:
static int[] cutTheSticks(int[] arr)
{
List<int> results = new List<int>();
int cutted = 0;
while (cutted != 1)
{
cutted = 0;
int min = GetMin(arr);
if (min == 0)
{
break;
}
for (int i = 0; i < arr.Length; i++)
{
if (arr[i] >= min)
{
arr[i] -= min;
cutted++;
}
}
results.Add(cutted);
}
return results.ToArray();
}
static int GetMin(int[] arr)
{
int min = int.MaxValue;
for (int i = 0; i < arr.Length; i++)
{
if (arr[i] != 0 && arr[i] < min)
{
min = arr[i];
}
}
return min;
}

Returns incorrect output

Description of challenge:
Have the function KaprekarsConstant(num) take the num parameter being passed which will be a 4-digit number with at least two distinct digits.
Your program should perform the following routine on the number:
Arrange the digits in descending order and in ascending order (adding
zeroes to fit it to a 4-digit number), and subtract the smaller
number from the bigger number. Then repeat the previous step.
Performing this routine will always cause you to reach a fixed number: 6174.
Then performing the routine on 6174 will always give you 6174 (7641 - 1467 = 6174).
Your program should return the number of times this routine must be performed until 6174 is reached.
For example: if num is 3524 your program should return 3 because of the following steps:
5432 - 2345 = 3087
8730 - 0378 = 8352
8532 - 2358 = 6174
Web-site where I took this challenge Coderbyte
Problem :
All works correctly until returning the result in Foo() I don't know why but it calls this function some times until Count==2
Please help.Sorry please if I made mistakes and my code is really bad because I am schooler(9 Grade) and I have been programming for half a year
using System;
class MainClass
{
public static int Foo(int num,int Counter)
{
int Count = Counter;
int[] arr = new int[4];
arr[0] = num / 1000;
arr[1] = num % 10;
arr[2] = (num / 100) % 10;
arr[3] = (num % 100) / 10;
Array.Sort(arr);
int[] AscArr = new int[4];
arr.CopyTo(AscArr, 0);
Array.Reverse(arr);
int[] DescArr = arr;
int sub = 0;
string AscStr = string.Empty;
string DescStr = string.Empty;
for (int i = 0; i < AscArr.Length; i++)
{
AscStr += AscArr[i];
}
for (int i = 0; i < DescArr.Length; i++)
{
DescStr += DescArr[i];
}
int b = int.Parse(AscStr);
int a = int.Parse(DescStr);
sub = a - b;
if (sub!=6174)
{
Count++;
Foo(sub,Count);
}
if (sub==6174)
{
Count++;
}
return Count;
}
public static int KaprekarsConstant(int num)
{
int[] arr=new int[4];
arr[0] = num / 1000;
arr[1] = num % 10;
arr[2] = (num / 100) % 10;
arr[3] = (num % 100) / 10;
Array.Sort(arr);
int[] AscArr=new int[4];
arr.CopyTo(AscArr,0);
Array.Reverse(arr);
int[] DescArr = arr;
int sub = 0 ;
string AscStr=string.Empty;
string DescStr = string.Empty;
for (int i = 0; i < AscArr.Length; i++)
{
AscStr += AscArr[i];
}
for (int i = 0; i < DescArr.Length; i++)
{
DescStr += DescArr[i];
}
int b = int.Parse(AscStr);
int a = int.Parse(DescStr);
sub = a - b;
int Counter =1;
int Count=0;
if (Count!=6174)
{
Count = Foo(sub, Counter);
}
return Count;
}
static void Main()
{
// keep this function call here
Console.WriteLine(KaprekarsConstant(int.Parse(Console.ReadLine())));
}
}
Your code is too much complex, plus, your way of dividing number to array is giving wrong results.
// this is wrong you can print array, the numbers goes into wrong indexes
arr[0] = num / 1000;
arr[1] = num % 10;
arr[2] = (num / 100) % 10;
arr[3] = (num % 100) / 10;
Use this:
using System;
class MainClass
{
public static int count = 0;
public static void KaprekarsConstant(int num)
{
if (num == 6174) // base case
return;
count++;
string[] Aarr=new string[4];
string[] Darr = new string[4];
string asc = "", dsc = "";
Aarr[3] = (num % 10).ToString();
Darr[3] = (num % 10).ToString();
num /= 10;
Aarr[2] =(num % 10).ToString();
Darr[2] = (num % 10).ToString();
num /= 10;
Aarr[1] = (num % 10).ToString();
Darr[1] = (num % 10).ToString();
num /= 10;
Aarr[0] =(num % 10).ToString();
Darr[0] = (num % 10).ToString();
Array.Sort(Aarr); // ascneding sorted
Array.Sort<string>(Darr, new Comparison<string>( (i1, i2) => i2.CompareTo(i1))); // descending sorted
for(int i = 0; i< 4;i++)
{
asc += Aarr[i];
dsc += Darr[i];
}
KaprekarsConstant(Convert.ToInt32(dsc) -Convert.ToInt32(asc) );
}
static void Main()
{
KaprekarsConstant(int.Parse(Console.ReadLine()));
Console.WriteLine("\nIt took "+count + "times to reach 6174");
}
}

Largest substring composed of identical characters

I want to develop method that will return the length of largest substring composed of identical characters form string that is passed as argument, but without using any of .NET libraries.
For example if we pass aaacccccdefffgg as parameter the biggest substring is ccccc and method should return 5.
Here is my working solution :
public static int GetMaxSubstringLenght(char[] myArray)
{
int max = 0;
for (int i = 0; i < myArray.Length-1; i++)
{
if (myArray.Length == 0)
{
return 0;
}
else
{
int j = i + 1;
int currentMax = 1; // string has some value, so we start with 1
while (myArray[i] == myArray[j])
{
currentMax++;
if (max < currentMax)
{
max = currentMax;
}
j++;
}
}
}
return max;
}
The code above will return expected result, but there will be some unnecessary iteration in for loop that I want to avoid. In first iteration when i=0it will compare it until j=2 and then will get out of while loop and start second iteration in for loop comparing the one at [1] index with [2], which we already did in previous iteration.So basically, when first iteration is completed, next one should start from the last value of j. How can I achieve that ?
Thank You in advance.
Since you want "Largest substring..." let's take String as argument and return String
public static String GetMaxSubstring(String value) {
if (String.IsNullOrEmpty(value))
return "";
int bestCount = 0;
char bestChar = '\0';
int currentCount = 0;
char current = '\0';
for (int i = 0; i < value.Length; ++i) {
if ((i == 0) || (value[i] != current))
currentCount = 0;
currentCount += 1;
current = value[i];
if (currentCount > bestCount) {
bestCount = currentCount;
bestChar = current;
}
}
return new String(bestChar, bestCount);
}
....
// "ccccc"
String result = GetMaxSubstring("aaacccccdefffgg");
// 5
int length = result.Length;
Another approach:
public static int MaxSubstringLength(string s)
{
if (string.IsNullOrEmpty(s))
return 0;
int max = 0, cur = 1;
for (int i = 1; i < s.Length; ++i, ++cur)
{
if (s[i] != s[i-1])
{
max = cur > max ? cur : max;
cur = 0;
}
}
return cur > max ? cur : max;
}
[EDIT] Simplified the code.
[EDIT2] Simplified the code further.
you also can do it with one loop:
public static int GetMaxSubstringLenght(char[] myArray)
{
int max = 0;
char currentchar = myArray[0];
int count = 1;
for each(char c in myArray)
{
if(currentchar != c)
{
count = 1;
currentchar = c;
}
if(count > max)
{
max = count;
}
count++;
}
return max;
}
I changed the code... now this code does not use math.max and I think I eleminated the mistake... I've no IDE at the moment to test it
public static int GetMaxSubstringLenght(char[] myArray)
{
if (myArray.Length == 0)
return 0;
if (myArray.Length == 1)
return 1;
int max = 1;
int localMax = 1;
for (int i = 0; i < myArray.Length - max; i++ )
{
if (myArray[i] == myArray[i + 1])
{
localMax++;
}
else
{
max = Math.Max(max, localMax);
localMax = 1;
}
}
return Math.Max(max, localMax);
}
static int LongestCharSequence(string s)
{
if (string.IsNullOrEmpty(s)) return 0;
var prevChar = '\0';
int cmax = 0;
int max = 1;
foreach (char c in s)
{
if (c != prevChar)
{
cmax = 1;
prevChar = c;
}
else
{
if (++cmax > max) max = cmax;
}
}
return max;
}
recursion!
static int LongestCharSequence(string s)
{
int i = (s?.Length ?? 0) == 0 ? 0 : 1;
for (; i < s?.Length; i++)
if (s[i] != s[i - 1]) return Math.Max(i, LongestCharSequence(s.Substring(i)));
return i;
}
Another solution using my favorite nested loop technique:
public static int MaxSubstringLength(string s)
{
int maxLength = 0;
for (int length = s != null ? s.Length : 0, pos = 0; pos < length;)
{
int start = pos;
while (++pos < length && s[pos] == s[start]) { }
maxLength = Math.Max(maxLength, pos - start);
}
return maxLength;
}

Clean algorithm to generate all sets of the kind (0) to (0,1,2,3,4,5,6,7,8,9)

Basically, I'd like a set of sets that contains from (0..9), then (0, 1..9), (1, 2..9)..(8,9), and so on and so forth up until (0,1,2,3,4,5,6,7,8,9). I know this can be accomplished by nesting for loops in the manner below, but I'm wondering if there's a neater way of doing it?
Preferably something that could be accomplished within C#, but I'm interested in any algorithm.
for (int i = 0; i < max; i++) {
yield {i};
for (int j = i + 1; j < max; j++) {
yield {i, j};
for (int k = j + 1; k < max; k++) {
yield {i, j, k};
for (int l = k + 1; l < max; l++) {
yield {i, j, k, l};
for (int m = l + 1; m < max; m++) {
yield {i, j, k, l, m};
// And so on and so forth
}
}
}
}
}
I wrote this a while ago. It uses a Stack. It's generic, so it can be used for other sequences as well.
static IEnumerable<T[]> CombinationsAnyLength<T>(params T[] values)
{
Stack<int> stack = new Stack<int>(values.Length);
int i = 0;
while (stack.Count > 0 || i < values.Length) {
if (i < values.Length) {
stack.Push(i++);
int c = stack.Count;
T[] result = new T[c];
foreach (var index in stack) result[--c] = values[index];
yield return result;
} else {
i = stack.Pop() + 1;
if (stack.Count > 0) i = stack.Pop() + 1;
}
}
}
CombinationsAnyLength(1, 2, 3, 4) outputs:
1
12
123
1234
124
13
134
14
2
23
234
24
3
34
4
Why not treat this as bits and generate the set from the bits?
IEnumberable<List<int>> MakeSets()
{
// count from 1 to 2^10 - 1 (if you want the empty set, start at 0
for (uint i=1; i < (1 << 10); i++) {
// enumerate the bits as elements in a set
List<int> set = BitsIn(i);
yield return set;
}
}
List<int> MakeSet(uint i)
{
List<int> set = new List<int>();
// this will give you values from 0..max
// if you want 1, start with 1
// if you want non-integers, pass in an array of values and index into that
int val = 0;
// for every bit in i
while (i != 0)
{
// add the val if the corresponding bit is set
if ((i & 1) != 0) set.Add(val);
i = i >> 1;
val++;
}
return set;
}
and since I like the generic version above, let's make this generic too:
IEnumerable<List<T>> MakeSets(params T[] values)
{
if (values.Length > 63) throw new IllegalArgumentException("63 is the limit");
for (ulong i = i; i < (1 << (values.Length + 1); i++) {
List<T> set = new List<T>();
int val = 0;
ulong j = i;
while (j != 0) {
if ((j & 1) != 0) set.Add(values[val]);
j = j >> 1;
val++;
}
yield return set;
}
}
here is a algorithm for generating sub-sets.
let you have a set S = [a,b,c,d,e,f].
and you want to generate all the subsets then length of the array containing all the sub-sets will be
2^n where n is number of elements in S.
int A = [] // array containing all sub-sets
for i = 0 --- 2^n
x = binary(i) // like for i = 5 -> x = '000101' where x is a string of n digits.
ns = [] // new array
for j = 0 --- n
if x[j] == '1'
push S[j] into ns array
push ns into A
return A
A will have every set you wanted or you can modify it to get new result.
Using Dennis signature:
public static IEnumerable<T[]> CombinationsAnyLength<T>(params T[] values)
{
for(var i = 0; i < (1 << values.Length); i++)
{
var result = new List<T>();
for(var j = 0; j < values.Length; j++)
{
if(((1 << j) & i) != 0)
{
result.Add(values[j]);
}
}
yield return result.ToArray();
}
}

Categories

Resources