Recursion in place of multiple nested for loops? - c#

Im having some issues with trying to update a nested for loop to use recursion instead. Is it possible to access the a,b and c variables from the earlier for loops when using recursion? Below is a simple example of what im trying to convert into a recursive call.
for(int a= 0; a < 10; a++)
{
for(int b = 0; b < 20; b++)
{
for(int c = 0; c < 10; c++)
{
int[] indexes = new int[3]{a,b,c}
collection.add(indexes);
}
}
}
EDIT: The solution needs to be able to be adjusted at runtime, such that a user can select how many levels are required.

Here's a recursive solution (using a functional programming style):
public static IEnumerable<IEnumerable<int>> GetCombinations(IEnumerable<int> limits)
{
if (limits.Any() == false)
{
// Base case.
yield return Enumerable.Empty<int>();
}
else
{
int first = limits.First();
IEnumerable<int> remaining = limits.Skip(1);
IEnumerable<IEnumerable<int>> tails = GetCombinations(remaining);
for (int i = 0; i < first; ++i)
foreach (IEnumerable<int> tail in tails)
yield return Yield(i).Concat(tail);
}
}
// Per http://stackoverflow.com/q/1577822
public static IEnumerable<T> Yield<T>(T item)
{
yield return item;
}
Sample use:
var sequences = GetCombinations(new [] { 5, 3, 2, 4 /* ... */ });
foreach (var sequence in sequences)
Console.WriteLine(string.Join(", ", sequence));
/* Output:
0, 0, 0, 0
0, 0, 0, 1
0, 0, 0, 2
0, 0, 0, 3
0, 0, 1, 0
0, 0, 1, 1
0, 0, 1, 2
0, 0, 1, 3
0, 1, 0, 0
0, 1, 0, 1
0, 1, 0, 2
... */
For OP's specific scenario (adding arrays to collection):
var sequences = GetCombinations(new [] { 10, 20, 10 });
collection.AddRange(sequences.Select(s => s.ToArray()));

Ok, try with this
static void AddToCollectionRecursive(
List<int[]> collection,
params int[] counts)
{
AddTo(collection, new List<int>(), counts, counts.Length - 1);
}
static void AddTo(
List<int[]> collection,
IEnumerable<int> value,
IEnumerable<int> counts,
int left)
{
for (var i = 0; i < counts.First(); i++)
{
var list = value.ToList();
list.Add(i);
if (left == 0)
{
collection.Add(list.ToArray());
}
else
{
AddTo(collection, list, counts.Skip(1), left - 1);
}
}
}
Usage is like this AddToCollectionRecursive(collection, 10, 20, 10);.

something like this will work:
public void CreateIndexes(int a, int b, int c, Collection collection)
{
if(c == 10) {b++; c = 0;}
if(b == 20) {a++; b = 0;}
if(a == 10) return;
int[] indexes = new int[3]{a,b,c}
collection.add(indexes);
c++;
CreateIndexes(a, b, c, collection);
}

Off the top of my head, i.e. not tested, something like this might work:
List<int[]> collection = new List<int[]>();
private void AddValues(int a, int b, int c)
{
collection.Add(new[] { a, b, c });
if (c < 10)
{
c++;
AddValues(a, b, c);
}
if (b < 20)
{
b++;
c = 0;
AddValues(a, b, c);
}
if (a < 10)
{
a++;
b = 0;
c = 0;
AddValues(a, b, c);
}
}
Start it by calling:
AddValues(0, 0, 0);

Well, i think that if u resolve this problem using recursion, it will consume more memory and other resources!
But there is my suggestion:
private void FunctionName(int a, int b, int c, List<int[]> list)
{
if (a<10)
{
if (b<20)
{
if (c<10)
{
list.Add(new[] { a, b, c });
c++;
FunctionName(a,b,c,list);
}
else
{
c=0;
b++;
FunctionName(a,b,c,list);
}
}
else
{
b=0;
a++;
FunctionName(a,b,c,list);
}
}
}
You call like this : FunctionName(0,0,0,list).
Hope it works! ^^

This solution takes an Action for the work to be done at the leafs:
void ForEachCombo(int from, int to, int nrLevels, Action<int[]> action)
{
int[] d = new int[nrLevels];
InnerFor(from, to, 0);
void InnerFor(int from, int to, int level)
{
if (level == nrLevels)
action(d);
else
for (d[level] = from; d[level] <= to - nrLevels + level + 1; d[level]++)
InnerFor(d[level] + 1, to, level + 1);
}
}
Use like this:
ForEachCombo(0, 9, 3, (d) =>
{
Console.WriteLine(string.Join(", ", d));
});
// Output
0, 1, 2
0, 1, 3
0, 1, 4
0, 1, 5
...
6, 7, 9
6, 8, 9
7, 8, 9
//
If you want to you can save a level of recursion by writing like this:
void ForEachCombo(int from, int to, int nrLevels, Action<int[]> action)
{
int[] d = new int[nrLevels];
InnerFor(from, to, 0);
void InnerFor(int from, int to, int level)
{
if (level == nrLevels - 1)
for (d[level] = from; d[level] <= to - nrLevels + level + 1; d[level]++)
action(d);
else
for (d[level] = from; d[level] <= to - nrLevels + level + 1; d[level]++)
InnerFor(d[level] + 1, to, level + 1);
}
}

Related

Summing special object array of ints and objects

I have a List<object> which can contain either an integer value or another List<object>.
What I need to do, is to sum the values in the array, depending on its depth(If depth is 0, multiply by 0, if 1 then by 1 ... etc.)
Example array: [5, 2, [7, -1], 3, [6, [-13, 8], 4]]
How it should be calculated: 5 + 2 + 2 * (7 - 1) + 3 + 2 * (6 + 3 * (-13 + 8) + 4) = 12
What I managed to get:
public class Program
{
public static List<object> TestCase1()
{
List<object> test = new List<object>(){
5,
2,
new List<object>(){
7, -1
},
3,
new List<object>(){
6,
new List<object>(){
-13, 8
},
4,
},
};
return test;
}
public static int ProductSum(List<object> array)
{
int depthCounter = 1;
int totalSum = 0;
int tempSum = 0;
for (int i = 0; i < array.Count; i++)
{
if (array[i] is IList<object>)
{
totalSum += tempSum * depthCounter;
tempSum = 0;
depthCounter++;
}
else
{
tempSum += (int)array[i];
}
}
return totalSum;
}
static void Main(string[] args)
{
Console.WriteLine("Result = " + ProductSum(TestCase1()));
}
}
The result from my code is
The problem that I have, is I don't see a way, that I could iterate through an array to calculate it ... Maybe there is a way to sort an array of objects in some way to simplify it?
The method should call itself ("recursive"), when it encounters a nested list. It should also take a depth parameter, keeping track of the depth. Every time you call the function recursively, you pass depth + 1 as the new depth. Whenever you count something, you multiply by depth.
public static int ProductSum(List<object> list) => ProductSum(list, 1);
public static int ProductSum(List<object> list, int depth)
{
var sum = 0;
foreach (var thing in list) {
if (thing is List<object> innerList) {
sum += ProductSum(innerList, depth + 1) * depth;
} else if (thing is int x) {
sum += x * depth;
}
}
return sum;
}
You should do it recusively:
public static int ProductSum(List<object> array, int depthCounter)
{
int totalSum = 0;
for (int i = 0; i < array.Count; i++)
{
if (array[i] is List<object>)
{
totalSum += ProductSum(array[i] as List<Object>, depthCounter + 1);
}
else
{
totalSum += (int)array[i] * depthCounter;
}
}
return totalSum;
}
You call it this way:
ProductSum(TestCase1(), 0);
But I don't get the number you calculated, though: If all depth 0 candidates are multiplied by 0, these are... 0! ;)
Maybe there are some rules for your application that I don't know, and that's the reason why the calculations differ, but in the code you see how recursions work.

How to display all included numbers in KnapSack problem?

I have a problem with displaying used numbers. I'm using KnapSack algorithm and I want to display all numbers that I used to get highest value. So there is my code:
static int max(int a, int b)
{
int c = (a > b) ? a : b;
Console.WriteLine(c);
return (a > b) ? a : b;
}
// Returns the maximum value that can
// be put in a knapsack of capacity W
int knapSack(int[] r, int[] wt, int n, int W)
{
if (W < 0)
return Int32.MinValue;
if (n < 0 || W == 0)
return 0;
int include = r[n] + knapSack(r, wt, n, W - wt[n]);
int exclude = knapSack(r, wt, n - 1, W);
int V = max(include, exclude);
return V;
}
Use:
int[] r = new int[] { 3, 4, 8, 5, 6 };
int[] wt = new int[] { 2, 2, 3, 4, 7 };
int W = 11;
int z = W;
int n1 = r.Length;
stopwatch.Start();
int keik = knapSack(r, wt, n1 - 1, W);
stopwatch.Stop();
answer of this is 28, but I need to display all r numbers that was included in this. I know that for this array used numbers are 8 8 8 and 4, so I need somehow to get these numbers and display to the console.
You could try the approach of letting the function return the list of used items.
You could either return the item values themselves, or the indices of the values, depending on your needs. I used the values in this example.
Here is an implementation:
static int knapSack(int[] r, int[] wt, int n, int W, out List<int> list)
{
if (W < 0) {
list = new List<int>();
return Int32.MinValue;
}
if (n < 0 || W == 0) {
list = new List<int>();
return 0;
}
int include = r[n] + knapSack(r, wt, n, W - wt[n], out List<int> includedList);
int exclude = knapSack(r, wt, n - 1, W, out List<int> excludedList);
if (include > exclude) {
includedList.Add(r[n]);
list = includedList;
return include;
} else {
list = excludedList;
return exclude;
}
}
Call like this:
int keik = knapSack(r, wt, n1 - 1, W, out List<int> list);
Console.WriteLine(string.Join(",", list));
Output:
4,8,8,8

Stack overflow while using recursive function

I am trying to do a simple coding challenge that requires me to do the following:
You are given n, return an array ans, composed in such way:
`ans = [n, n - 5, n - 10, ... , m, m + 5, ... , n - 5, n]`, where m stands for the first non-positive integer obtained by subtractions.
Try to solve it without any loop.
Example
For n = 25, the output should be
listWithoutLoop(n) = [25, 20, 15, 10, 5, 0, 5, 10, 15, 20, 25].
I have done this code:
int[] listWithoutLoop(int n)
{
List<int> test = new List<int>();
if (test.Count > 2 && test[test.Count - 1] == n)
return test.ToArray();
if (n <= 0)
{
test.Add(n + 5);
return listWithoutLoop(n + 5);
}
else
{
test.Add(n - 5);
return listWithoutLoop(n - 5);
}
}
But I keep getting a stack overflow when running it. Is recursion supported by c#? If so, how to prevent getting a stackoverflow exception when running it?
You must define the test list above the listWithoutLoop() method.
List<int> test = new List<int>();
int[] listWithoutLoop(int n)
{
....
}
To simplify, I splitted the function to add up and add down separately (it's always better to have simple and understandable code at all times)
static void Main()
{
int n = 20;
int interval = 5;
List<int> list = new List<int>();
AddDown(list, n, 0, interval);
AddUp(list, 0, n, interval);
int[] arrInt = list.ToArray();
}
static void AddDown(List<int> list, int currentNumber, int targetNumber, int interval)
{
if(currentNumber > targetNumber)
{
list.Add(currentNumber);
AddDown(list, currentNumber - interval, targetNumber, interval);
}
}
static void AddUp(List<int> list, int currentNumber, int targetNumber, int interval)
{
if (currentNumber <= targetNumber)
{
list.Add(currentNumber);
AddUp(list, currentNumber + interval, targetNumber, interval);
}
}

Generate Gauss numbers

I have this problem with generating Gauss Numbers. The problem is like this :
This is what i coded so far
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace SirurileLuiGauss
{
class Program
{
static int[] a = new int[100];
static int[] b = new int[100];
static List<int> list_a = new List<int>();
static List<int> list_b = new List<int>();
static int GaussA(int n)
{
if(n <= 0)
{
int a = 0;
list_a.Add(a);
return a;
}
else
{
int a = (GaussA(n - 1) + GaussB(n - 1))/2;
list_a.Add(a);
return a;
}
}
static int GaussB(int n)
{
if(n <= 0)
{
int b = 0;
list_b.Add(b);
return b;
}
else
{
int b = (int) Math.Sqrt(GaussA(n - 1) * GaussB(n - 1));
list_b.Add(b);
return b;
}
}
static void Main(string[] args)
{
int n = 5;
Console.WriteLine("GAUSS_111");
GaussA(n);
foreach (int element in list_a)
{
Console.WriteLine("GAUSS_A = "+element);
}
foreach (int element in list_b)
{
Console.WriteLine("GAUSS_B = " + element);
}
Console.WriteLine("\n\n");
// Clear the list
list_a = new List<int>();
list_b = new List<int>();
Console.WriteLine("GAUSS_222");
GaussB(n);
foreach (int element in list_a)
{
Console.WriteLine("GAUSS_A = " + element);
}
foreach (int element in list_b)
{
Console.WriteLine("GAUSS_B = " + element);
}
Console.Read();
}
}
}
And is totally wrong, gives me the output like 0 0 0 0 ...
What am i doing wrong?
Can i find this anywhere? Like a library or something?
I thing that the approach of this is by computing the integral and find out what is the peak/max_number of the array. Then try to iterate backwards to find all the numbers until we hit a > 0 and b > 0. The main problem is that you have to keep 2 arrays into memory, and that is hard ... Am i correct?
How do i compute that integral in C# ?
Why do you need epsilon for precision?
Thank you very much.
The problem starts as "let a0 = ... b0 = ..."; so you need a0 as well as b0
being input arguments. Another issue is that you don't need any array or list here
(imagine, that you're asked to find out a millionth itteration), dynamic programming
is a far better choice here:
// I let myselft return the result as Tupple<,>
public static Tuple<Double, Double> Gauss(Double a0, Double b0, int n) {
Double prior_a;
Double prior_b;
Double a = a0;
Double b = b0;
for (int i = 0; i < n; ++i) {
prior_a = a;
prior_b = b;
a = (prior_a + prior_b) / 2.0;
b = Math.Sqrt(prior_a * prior_b);
}
return new Tuple<Double, Double>(a, b);
}
Simple test: let a0 = 1; b0 = 5, so we have
Theory:
itt # a b
0 1 5
1 3 sqrt(5)
2 (3+sqrt(5))/2 sqrt(3*sqrt(5))
Actual:
Gauss(1, 5, 0); // returns (1, 5)
Gauss(1, 5, 1); // -/- (3, 2.23606797749979)
Gauss(1, 5, 2); // -/- (2.61803398874989, 2.59002006411135)
Gauss(1, 5, 3); // -/- (2.60402702643062, 2.60398935469938)
Gauss(1, 5, 10); // -/- (2.60400819053094, 2.60400819053094)
Gauss(1, 5, 100); // -/- (2.60400819053094, 2.60400819053094)
P.S. You can't compute (get, say, double value) an indefinite integral cause it equals F(x) + C where C is arbitrary constant; for definite integtral you may use Simpson algorithm

Separating values in list when it decrease and increase

This is what I would like to do.
I have huge number of number in a list, but it has a sequence of either increasing or decreasing.
Such as,
100
200
300
400
500
600
500
400
300
200
100
500
700
800
900
Lets say this values are stored in a list or maybe an array. How could I separate these to multiple arrays or list consisting of the sequence.
Such as, List 1: 100 200 300 400 500 600
List 2 :500 400 300 200 100
List 3:500 700 800 900
This is what I have done. I am stuck.
for (int i = 0; i < p.Count - 1; i++)
{
double v = p.ElementAt(i);
if (initialP > v)
{
if (low == 1)
{
sep.Add(sep_index);
low = 0;
}
else
{
}
high = 1;
}
if (initialP < v)
{
if (high == 1)
{
sep.Add(sep_index);
high = 0;
}
low = 1;
}
initialP = v;
sep_index++;
if (i == p.Count - 2)
{
sep.Add(sep_index);
}
}
As suggested in the comments, you should use a list of of lists and while looping use a new list when there is a switch in the direction of the sort:
EDIT: Fixed to take into account equal numbers and strict comparaisons.
public static List<List<int>> GetLists(int[] nums, bool strict) {
List<List<int>> lists = new List<List<int>>();
List<int> list = new List<int>();
lists.Add(list);
list.AddRange(nums.Take(1));
if (nums.Length <= 1) {
return lists;
}
if (strict && nums[0] == nums[1]) {
list = new List<int>();
lists.Add(list);
list.Add(nums[1]);
}
else
list.Add(nums[1]);
if (nums.Length == 2)
{
return lists;
}
int direction = Math.Sign(nums[2] - nums[1]);
for (int i = 2; i < nums.Length; i++) {
int d = Math.Sign(nums[i] - nums[i - 1]);
if ((d == direction && (d != 0 || !strict))
|| (d != 0 && strict)
|| (Math.Abs(d + direction) == 1 && !strict))
{
list.Add(nums[i]);
if (d != 0 && direction == 0) direction = d;
}
else
{
direction = d;
list = new List<int>();
list.Add(nums[i]);
lists.Add(list);
}
}
return lists;
}
static void Main(string[] args)
{
int[] nums = new int[] { 2, 2, 2, 1, 1, 3, 3, 4, 4 };
var lists = GetLists(nums, false);
foreach (var list in lists) {
foreach (var item in list)
{
Console.Write(item + " ");
}
Console.WriteLine();
}
/*
* Prints:
* 2 2 2 1 1
* 3 3 4 4
* */
}
Derivation, or spin. If it is positive -- one direction. Otherwise -- another.
Use spin, which will show you direction (up or down): (n+1/n). When spin changes, then store elements in a list.
Possible solution:
public static IList<IList<int>> UpDownSeparator(IEnumerable<int> value) {
if (Object.ReferenceEquals(null, value))
throw new ArgumentNullException("value");
List<IList<int>> result = new List<IList<int>>();
List<int> current = new List<int>();
result.Add(current);
// +1 - asceding, -1 - descending, 0 - to be determined later
int direction = 0;
foreach(int item in value) {
if (direction == 0) {
if (current.Count > 0) {
if (item > current[current.Count - 1])
direction = 1;
else if (item < current[current.Count - 1])
direction = -1;
}
current.Add(item);
}
else if (direction < 0) {
if (item > current[current.Count - 1]) {
direction = 1;
current = new List<int>() { item };
result.Add(current);
}
else
current.Add(item);
}
else {
if (item < current[current.Count - 1]) {
direction = -1;
current = new List<int>() { item };
result.Add(current);
}
else
current.Add(item);
}
}
return result;
}
....
List<int> list = new List<int>() { 100, 200, 300, 400, 500, 600, 500, 400, 300, 200, 100, 500, 700, 800, 900};
// [[100, 200, 300, 400, 500, 600], [500, 400, 300, 200, 100], [500, 700, 800, 900]]
IList<IList<int>> result = UpDownSeparator(list);
I would do something like this:
private static List<int[]> SplitOnDirection(int[] input)
{
List<int[]> output = new List<int[]>();
List<int> currentList = new List<int>();
bool? isRaising = null;
int? previousNumber = null;
foreach (int number in input)
{
// do we have a previous value?
if (previousNumber.HasValue)
{
// only if the number is different, then we have to check the direction.
if (number != previousNumber.Value)
{
bool isHigherNumber = (number > previousNumber.Value);
// do we already know if we start with raise/lowering
if (isRaising.HasValue)
{
// if we have a higher number and we're not raising, change direction.
if (isHigherNumber != isRaising.Value)
{
// We changed direction..
output.Add(currentList.ToArray());
currentList = new List<int>();
}
}
isRaising = isHigherNumber;
}
}
previousNumber = number;
currentList.Add(number);
}
// if we didn't changed direction, we should 'flush' these.
if (currentList.Count > 0)
output.Add(currentList.ToArray());
return output;
}
int[] input = new int[] { 100, 200, 300, 400, 500, 600, 500, 400, 300, 200, 100, 500, 700, 800, 900 };
List<int[]> output = SplitOnDirection(input);
Took around 20 min, but I would do something like this below. Using Java, I am sure could easily be written using other language syntax.
Input
1, 1, 1, -1, 2, 3, 4, 4, 4, 5, 6, 5, 4, 4, 3, 3, 6, 6, 2, 1, 5, 7, 8, 9
Output
1 1 1 -1
2 3 4 4 4 5 6
5 4 4 3 3
6 6
2 1
5 7 8 9
Code
public static void main(String[] args) {
int[] input = new int[]{1, 1, 1, -1, 2, 3, 4, 4, 4, 5, 6, 5, 4, 4, 3, 3, 6, 6, 2, 1, 5, 7, 8, 9};
List<List<Integer>> lists = split(input);
for (List<Integer> list : lists) {
for (Integer integer : list) {
System.out.print(integer+" ");
}
System.out.println("");
}
}
public static List<List<Integer>> split(int[] input) {
List<List<Integer>> listOfList = new ArrayList<List<Integer>>();
if(input.length >= 1) {
List<Integer> list = newList(listOfList, input[0]);
Order lastO = null;
int last = input[0];
for (int i = 1; i < input.length; i++) {
Order currentO = Order.getOrder(input[i], last);
boolean samePattern = Order.sameDirection(currentO, lastO);
if(lastO == null || samePattern) {
list.add(input[i]);
} else {
list = newList(listOfList, input[i]);
lastO = null;
}
if(currentO != Order.Equal){
lastO = currentO;
}
last = input[i];
}
}
return listOfList;
}
private static List<Integer> newList(List<List<Integer>> listOfList, int element) {
List<Integer> list = new ArrayList<Integer>();
listOfList.add(list);
list.add(element);
return list;
}
private static enum Order {
Less, High, Equal;
public static Order getOrder(int first, int second) {
return first > second ? High : first < second ? Less : Equal;
}
public static boolean sameDirection(Order current, Order last) {
if(last == Order.Less && (current == Order.Less || current == Order.Equal)) {
return true;
} else if(last == Order.High && (current == Order.High || current == Order.Equal)) {
return true;
}
return false;
}
}

Categories

Resources