I am trying to find the sum of a list in a recursive algorithm
i am learning recursive algorithm, i know i can do it in another way but i am learning
this is my code (pretty simple)
class SumList
{
public SumList(int[] list ) {
List<int> listInteger = new List<int>();
for (int i = 0; i < list.Length; i++)
listInteger.Add(list[i]);
sum(listInteger);
}
private double sum(List<int> list) {
if (list.Count == 1)
{
return list[0];
}
if(list.Count ==2)
{
Console.Write(printList(list));
Console.WriteLine((list[0] + list[1]));
return list[0] + list[1];
}
double last = list[list.Count - 1];
List<int> backupList = new List<int>(list);
list.RemoveAt(list.Count -1);
double s = last + sum(list);
Console.Write(printList(backupList));
Console.WriteLine(s);
return s;
}
private string printList(List<int> list)
{
string result = "";
for (int i = 0; i < list.Count; i++)
{
result += list[i];
if (i != list.Count - 1)
{
result +="+ ";
}
else
{
result+= " = ";
}
}
return result;
}
}
and this call it like this:
int []listInt = new int[] { 4, 5, 6, 7, 9 , 10 };
new SumList(listInt);
Console.ReadLine();
my problem is that the result is:
i would like to have the result but like this:
4 + 5 + 6 + 7 = ...
4 + 5 + 6 = ...
so the results should be printed backwards
again i do know that there are millinos of way to find the sum of a list, but am trying to learn recursive algorithsm
As you probably know, a recursive function is a function that calls itself. This means that in order to solve a problem recursively, we must divide the problem in to steps such that the procedure will not change between steps, but the input to the function will change. Moreover, if our recursive function is ever to correctly terminate, the problem must get "smaller" with each step we take. This step represents one unit of recursion. Also, unlike with "normal" iteration, we do not know ahead of time when we are going to reach the end of the problem. Therefore, we need a mechanism to determine when we have reached the end of the problem and should stop recursing. This is known as the base case.
Let's try your example of finding the sum of a list.
The first thing we must do is come up with a unit of recursion (one abstract step that we can repeat over and over until we find the solution).
We know we have an input type of List<int>
In this case we can notice (psuedocode here) that sum(list) == list[0] + sum(restOfList). Notice that now we have a definite value (list[0]) and an object of type List<int> (namely restOfList).
So, now we have a neat, repeatable procedure.
//Idk what language you are using, or if it matters, but I am writing this in java
public int sum(List<Integer> list) {
//still need a base case
return list.get(0) + sum(list.subList(1, list.size()));
}
Now we only need to determine the base case. So we need to determine when we will have gone through all the elements of the list.
For this let's run through a few steps to see what will happen. Let's start with the following list: {1, 2, 3, 4}
sum({1, 2, 3, 4})
-> 1 + sum({2, 3, 4})
-> 2 + sum({3, 4})
-> 3 + sum({4})
-> 4 + oops!!!
Clearly, we cannot get the sublist beginning at index 1 from a list of size 1. This gives us the answer for what our base case should be.
public int sum(List<Integer> list) {
printList(list);
//base case
if (list.size() == 1)
return list.get(0); //recall that this is the entire list
//otherwise, continue to next step.
return list.get(0) + sum(list.subList(1, list.size()));
}
The addition works because the return statement of the first step is dependent on the return statement of the second step and so on. This is also why the steps will print in reverse order.
Just for clarity, let's trace through it one final time.
sum({1, 2, 3, 4}) //sum({1, 2, 3, 4}) is called from main()
-> 1 + sum({2, 3, 4}) //sum({2, 3, 4}) is called from sum({1, 2, 3, 4})
-> 2 + sum({3, 4}) //sum({3, 4}) is called from sum({2, 3, 4})
-> 3 + sum({4}) //sum({4}) is called from sum({3, 4})
<- 4 //sum({4}) returns 4 to sum({3, 4})
3 + 4
<- 7 //sum({3, 4}) returns 7 to sum({2, 3, 4})
2 + 7
<- 9 //sum({2, 3, 4}) returns 9 to sum({1, 2, 3, 4})
1 + 9
<- 10 //sum({1, 2, 3, 4}) returns 10
I hope this helped make things a little bit clearer.
Or try this
public static int Sum(List<int> listOfInt)
{
if (listOfInt.Count == 1)
{
return Convert.ToInt32(listOfInt[0]);
}
else
{
return Convert.ToInt32(listOfInt[0]) + Sum(listOfInt.Skip(1).ToList());
}
}
Well, this is not how I would do it, and it definitely has a number of oddities. But if I try to preserve the spirit behind your design, then I think a good way to accomplish this is by buffering the output in a StringBuilder, and using its Insert(0, str) method to place the lines in the right place.
public SumList(int[] list)
{
List<int> listInteger = new List<int>();
for (int i = 0; i < list.Length; i++)
listInteger.Add(list[i]);
StringBuilder output = new StringBuilder();
sum(listInteger, output);
Console.WriteLine(output.ToString());
}
private double sum(List<int> list, StringBuilder output)
{
if (list.Count == 1)
{
return list[0];
}
if (list.Count == 2)
{
output.Append(printList(list));
output.Append((list[0] + list[1])).Append(Environment.NewLine);
return list[0] + list[1];
}
double last = list[list.Count - 1];
List<int> backupList = new List<int>(list);
list.RemoveAt(list.Count - 1);
double s = last + sum(list, output);
output.Insert(0, Environment.NewLine);
output.Insert(0, s);
output.Insert(0, printList(backupList));
return s;
}
private string printList(List<int> list)
{
string result = "";
for (int i = 0; i < list.Count; i++)
{
result += list[i];
if (i != list.Count - 1)
{
result += " + ";
}
else
{
result += " = ";
}
}
return result;
}
Your code works by calculating the sums of all of the lists (and decreasing the lists as it goes) and then printing them going backwards, which explains why the lists you see are increasing in size. The way to fix this is by fixing your recursion. In order to have them printing in decreasing order, you want your recursion to go in increasing order. So, calculate sum(List.subList(1)), then sum(List.subList(2)), and so on...
An alternative quick fix is to save the output as a strings in an array and just print the array backwards.
One possible solution is
List<int> listInteger = new List<int> ();
public SumList (int[] list)
{
for (int i = 0; i < list.Length; i++)
listInteger.Add (list [i]);
listInteger.Reverse();
}
private void sumR (List<int> list, int index)
{
int sigma = 0;
if (list.Count - 1 == index) {
return;// sigma + list [index];
} else {
for (int i = list.Count-1; i>=index; i--) {
sigma += list [i];
if (i == list.Count - 1)
Console.Write ("{0} ", list [i]);
else
Console.Write ("+ {0} ", list [i]);
}
Console.WriteLine ("= {0}", sigma);
sumR (list, index + 1);
}
}
public void doSum(){
sumR(listInteger, 0);
}
There is no need for other methods, though you can call sumR from constructor if you like. Test is
int [] listInt = new int[] { 4, 5, 6, 7, 9 , 10 };
SumList sl = new SumList (listInt);
sl.doSum();
Console.ReadLine ();
Output is:
4 + 5 + 6 + 7 + 9 + 10 = 41
4 + 5 + 6 + 7 + 9 = 31
4 + 5 + 6 + 7 = 22
4 + 5 + 6 = 15
4 + 5 = 9
The recursive function:
public static void PrintSum(int[] list)
{
// Define the end of the recursion
if (list.Count() > 2)
// Copy the shorter list to PrintSum()
PrintSum(list.Take(list.Count() - 1).ToArray());
// Print the result of list AFTER shorter list is done
System.Diagnostics.Debug.WriteLine(
string.Format("{0} = {1}", string.Join("+ ", list),
list.Sum()));
}
public static void PrintSumReverse(int[] list)
{
// Print the result of list
System.Diagnostics.Debug.WriteLine(
string.Format("{0} = {1}", string.Join("+ ", list),
list.Sum()));
// Define the end of the recursion
if (list.Count() > 2)
// Copy the shorter list to PrintSum()
PrintSum(list.Take(list.Count() - 1).ToArray());
}
Usage:
var listInt = new int[] { 4, 5, 6, 7, 9, 10 };
PrintSum(listInt);
/* Result:
4+ 5 = 9
4+ 5+ 6 = 15
4+ 5+ 6+ 7 = 22
4+ 5+ 6+ 7+ 9 = 31
4+ 5+ 6+ 7+ 9+ 10 = 41
*/
PrintSumReverse(listInt);
/* Result
4+ 5+ 6+ 7+ 9+ 10 = 41
4+ 5+ 6+ 7+ 9 = 31
4+ 5+ 6+ 7 = 22
4+ 5+ 6 = 15
4+ 5 = 9
*/
Related
Is there anyway to achieve the following in C# (or any other ,Net language)?
public double nestedParamArrayLoop(function delegatedFunction, LoopControllers loopControllers)
{
double total = 0;
NestedLoopControllers loopControllers = new NestedLoopControllers(loopController, loopMaxes);
foreach(LoopController loopController in loopControllers);
{
nestedfor (loopController)
{
// this line results in one or more loopControllers being passed in
total += delegatedFunction(loopController);
}
}
return total;
}
public double delegatedFunction(params int[] arguments)
{
// dummy function to compute product of values
long product = 1;
for (int i = 0; i < arguments.Count ; i++)
product *= arguments[i];
return product;
}
Where delegatedFunction is called with a variable number of parameters, according to the number of controllers in the array loopControllers? Each loopController would contain a start value, a max value and an increment value (i.e. template a for loop).
The syntax above doesn't quite work as I'm not sure any exists to capture this paradigm. But the idea is that you can specify an arbitrary number of nested loops and then the nesting is done for you by the compiler (or the runtime). So it's a kind of templated nesting where you define the loop conditions for an arbitrary number of loops and the environment constructs the loops for you.
For example
NestedParamsArrayLoop(delegatedFunction, loopContoller1); results in iterated calls to delegatedFunction(values for loopValue1);
NestedParamsArrayLoop(delegatedFunction, loopContoller1, loopController2); results in
iterated calls to delegatedFunction(values for loopValue1, values for loopValue2);
NestedParamsArrayLoop(delegatedFunction, values for loopContoller1, values for values for loopController2, loopController3); results in
iterated calls to delegatedFunction(loopValue1, values for loopValue2, values for loopValue3);
The goal of this is to avoid writing separate functions with different numbers of arguments but where the actual guts of the logic is common across them.
I hope I've done a decent job of explaining this but if not please ask!
I think this is pretty much what you want to do.
Start with a LoopController definition:
public class LoopController : IEnumerable<int>
{
public int Start;
public int End;
public int Increment;
private IEnumerable<int> Enumerate()
{
var i = this.Start;
while (i <= this.End)
{
yield return i;
i += this.Increment;
}
}
public IEnumerator<int> GetEnumerator()
{
return this.Enumerate().GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
Now you can define NestedParamArrayLoop like so:
public double NestedParamArrayLoop(Func<int[], double> delegatedFunction, List<LoopController> loopControllers)
{
double total = 0;
foreach (LoopController loopController in loopControllers)
{
total += delegatedFunction(loopController.ToArray());
}
return total;
}
Now the rest is easy:
void Main()
{
var loopControllers = new List<LoopController>()
{
new LoopController() { Start = 4, End = 10, Increment = 2 },
new LoopController() { Start = 17, End = 19, Increment = 1 },
};
Console.WriteLine(NestedParamArrayLoop(DelegatedFunction, loopControllers));
}
public double DelegatedFunction(params int[] arguments)
{
long product = 1;
for (int i = 0; i < arguments.Count(); i++)
product *= arguments[i];
return product;
}
You could even define NestedParamArrayLoop as this:
public double NestedParamArrayLoop(Func<int[], double> delegatedFunction, List<LoopController> loopControllers)
{
return
loopControllers
.Select(lc => delegatedFunction(lc.ToArray()))
.Sum();
}
Is this more like what you're after?
public double NestedParamArrayLoop(Func<int[], double> delegatedFunction, List<LoopController> loopControllers)
{
Func<IEnumerable<int>, IEnumerable<IEnumerable<int>>> getAllSubsets = null;
getAllSubsets = xs =>
(xs == null || !xs.Any())
? Enumerable.Empty<IEnumerable<int>>()
: xs.Skip(1).Any()
? getAllSubsets(xs.Skip(1))
.SelectMany(ys => new[] { ys, xs.Take(1).Concat(ys) })
: new[] { Enumerable.Empty<int>(), xs.Take(1) };
double total = 0;
foreach (LoopController loopController in loopControllers)
{
foreach (var subset in getAllSubsets(loopController))
{
total += delegatedFunction(subset.ToArray());
}
}
return total;
}
Since the OP asked for a solution in any .NET language, I wrote one in F# (translating #Enigmativity's answer). No NestedLoopController class required:
[[ 4 .. 2 .. 10 ]; [ 17 .. 1 .. 19 ]]
|> Seq.map (fun args ->
(1L, args)
||> Seq.fold (fun a x -> a * int64 x))
|> Seq.sum
|> printfn "%d"
You can probably translate this to C# LINQ in a relatively straightforward way…
I think what you really need is what is called cartesian product of multiple sets. Here is good article from Eric Lippert about doing that with arbitrary number of sets in C#. So create function like this (I won't explain it because I cannot do this better than Eric did in his article):
static IEnumerable<IEnumerable<T>> CartesianProduct<T>(params IEnumerable<T>[] sources) {
IEnumerable<IEnumerable<T>> result = new[] { Enumerable.Empty<T>() };
foreach (var source in sources) {
var tmp = source;
result = result.SelectMany(
seq => tmp,
(seq, item) => seq.Concat(new[] { item }));
}
return result;
}
Then use like this:
foreach (var n in CartesianProduct(Enumerable.Range(1, 4), Enumerable.Range(1, 4))) {
Console.WriteLine(String.Join(", ", n));
// in your case: delegatedFunction(n);
}
outputs
1, 1
1, 2
1, 3
1, 4
2, 1
2, 2
2, 3
2, 4
3, 1
3, 2
3, 3
3, 4
4, 1
4, 2
4, 3
4, 4
It's easy to replace Enumerable.Range with your LoopController, Enumerable.Range is used just as an example.
What I am looking for isn't a problem solution but maybe a better c# logic.
Basically, I have a got a value which is a sum of any of those values {1, 2, 4}.
Then I will do some actions depends on those values in descending order.
Check the code below:
byte value = 7;//could be 1,2,3,4,5,6,7 which is the summation of any of those 3 numbers {1, 2, 4}
bool case1 = false, case2 = false, case3 = false;
if (value >= 4)
{
case1 = true;
value -= 4;
}
if (value >= 3)
{
case2 = true;
value -= 3;
}
if (value >= 1)
{
case3 = true;
value -= 1;
}
if (case3)
{
//do some action
}
if (case2)
{
//do some action
}
if (case1)
{
//do some action
}
Note that: Any of the numbers is not repeated in the summation.
That's what I have written in c#, But that doesn't make me feel good about the code logic in 2k17.
Hope someone has a better logic with any mathematical operation!
Thanks in advance.
(Edited again... code sample)
Instead of using an int, could you use an enum?
public enum MyEnum
{
Nothing = 0,
One = 1,
Two = 2,
Four = 4,
Seven = 7
}
MyEnum seven = MyEnum.Seven;
if( (seven & MyEnum.Four) == MyEnum.Four)
{
Console.WriteLine("Four");
}
if((seven & MyEnum.Two) == MyEnum.Two)
{
Console.WriteLine("Two");
}
if((seven & MyEnum.One) == MyEnum.One)
{
Console.WriteLine("One");
}
previous tip: bit masks, easy to understand examples here http://www.alanzucconi.com/2015/07/26/enum-flags-and-bitwise-operators/
I think your original code is wrong and the second if should be if (value >= 2) instead of if (value >= 3), but that's beside the point. If I understand what you want to achieve then this console application should be of help:
class Program
{
static void Main(string[] args)
{
int value = 7;
int copy = value; // only needed for the Console.WriteLine below
var allComponents = new[] { 4, 2, 1 };
var sumParts = new List<int>();
int i = 0;
while (i < allComponents.Length)
{
if (value >= allComponents[i])
{
value -= allComponents[i];
sumParts.Add(allComponents[i]); // or do some action whatever you need
}
i++;
}
Console.WriteLine("Value {0} is the sum of {1}", copy, string.Join(" + ", sumParts));
}
}
Outputs for the possible values (7, 6, 5, 4, 3, 2, 1):
Value 7 is the sum of 4 + 2 + 1
Value 6 is the sum of 4 + 2
Value 5 is the sum of 4 + 1
Value 4 is the sum of 4
Value 3 is the sum of 2 + 1
Value 2 is the sum of 2
Value 1 is the sum of 1
It's looping through all the components from largest to smallest (4, 2, 1), checking if the current one is larger or equal to the value, if yes, then decrements value by the current component and adds the current component to the sumParts list.
If you can invoke your logic from inside the if in the loop, then you don't even need the sumParts, just do whatever you need there.
This solution is basically the same as yours, but rolled into a loop instead of statements after each other.
I made some C# code that outputs a SortedDictionary <int index, list<int>values>> Where the index always starts with lowest int of the list<> that follows. Here is a short example of input (in reality the input is larger):
index- Values<>
2 - 2,3,6,7
3 - 3,5
5 - 5,7,9
11 - 11,12,12
Now I want to do some re-orderning in here. The values are linked indexes. I want to sort them so that connected indexes are grouped together, with no double indexes. That should result in output
2 - 2,3,5,6,7,9
11 - 11,12
Initially i had problems working with a sortedDictionary using a foreach while also decreasing the dictionary set size. I solved that, and now give an update of this problem description with my latest code. It doesnt use a foreach anymore, and some sorting problems seam to be fixed now, but as a side effect it became pretty complex and large. And i doubt if it should be so complex, or might be written shorter, more simple.
Each List i call a tree, where is thoe dictionary are trees
And Cursor or c i use like reading out text digit by digit from screen.
For the moment I put it in a small concept function code in a console app. Just to check if it all works. Testing is quite complex, since number sets can be complexly linked. So its not directly visible if you got lots of sets and a lots of number how they should be sorted. Therefore manually checking code validity and results isn't easy either.
While I am not yet sure if it now indeed does work for 100%. It seams to work better then before. But i think this code is far from perfect, as i walk the set of trees twice. With a pre-sort and a final-sort.
static SortedDictionary<int, List<int>> NewSort(SortedDictionary<int, List<int>> trees)
{
bool debugmode = false;
//pre sort
List<int> indexTree = new List<int>();
foreach (KeyValuePair<int, List<int>> tree in trees)
{
indexTree.Add(tree.Key);
}
for (int i = 0; i < indexTree.Count; i++)
{
int cursor = 1;
List<int> tree = new List<int>();
int index = indexTree[i];
tree = trees[index];
while ((tree !=null)&& (cursor<tree.Count) )
{
int c = tree[cursor ];
if (trees.ContainsKey(c))
{
if (trees[c] != null)
{
List<int> u = new List<int>();
u = trees[c];
tree.AddRange(u);
tree.Sort();
trees[index] = tree;
trees[c] = null;
}
}
cursor++;
}
}
for (int i = trees.Count; i > 0; i--)
{
int c = indexTree[i - 1];
if (trees[c] == null)
{ trees.Remove(indexTree[i - 1]); }
else
{
trees[c] = trees[c].Distinct().ToList(); //removing all duplicates
}
}
indexTree = new List<int>();
//resort.
foreach (KeyValuePair<int, List<int>> tree in trees)
{
indexTree.Add(tree.Key);
if(debugmode) Console.WriteLine("* " +DumpIntList(trees[tree.Key]));
}
for (int i = (indexTree.Count); i > 0; i--)
{
if (debugmode) Console.WriteLine(i.ToString());
List<int> tree = new List<int>();
tree = trees[indexTree[i-1]];
for (int j = 0; j < tree.Count; j++)
{
int c = tree[j];
for (int k = (i - 2); k > 0; k--)
{
List<int> compareTree = new List<int>();
compareTree = trees[indexTree[k]];
if (compareTree.IndexOf(c) != -1) // found !
{
if (debugmode) Console.Write("found " + c.ToString() + " from ");
if (debugmode) Console.WriteLine(DumpIntList(tree) + " in (" + DumpIntList(compareTree)+ ")");
tree.Remove(c); // or we would create a duplicate
compareTree.AddRange(tree);
compareTree = compareTree.Distinct().ToList(); //removing doubles again, doubles as side effect of merging
compareTree.Sort();
trees.Remove(indexTree[i - 1]);
trees[indexTree[k]] = compareTree;
}
}
}
}
return trees;
}
Maybe what i try to do inst that clear to some, what i try to do here is that i try to look if series have overlapping numbers, and if so merge them.
Where each series is always sorted and starts with the lowest number of that series. As I found recently this might be a version of the UnionFind problem. The problem also appears in Blob detection, and finding what web pages are link eachother in a set of webpages. (but my data is a strange set lab measurements).
The difficulty is that there are lots of series, and it might be not directly clear if they are connected
1-3-4
4-7-9
11-12
would result in 2 series :
1) 1-3-4-7-9
2) 11-12
But after you add series 12-3 then it would all become one series.
Some more test data :
2 - 2,3,5,6,7 // note my data is always ordered like this
5 - 5,7,9 // dictionary starts with lowest key
11 - 11,12,12,27,30,31 // each list inside a tree key
22 - 22,27 // is ordered low to high
23 - 23,25 // lowest int, equals the dict key.
28 - 28,30
34 - 34
Output using above function
2 - 2,3,5,6,7,9
11 - 11,12,22,27,28,30,31
23 - 23,25
34 - 34
So while the code seams to work now, I highly doubt its ideal code, i irritate the trees set twice. And so i wonder if better solutions are possible. It might also be that the code doesnt do what i hope it todo; as i'm still testing it.
Other than inverting an if to avoid 1 level of nesting, I don't yet see how LINQ can be used to improve the readability of this code block.
static SortedDictionary<int, List<int>> SortTree(SortedDictionary<int, List<int>> trees)
{
//SortedDictionary<int, List<int>> newtrees = new SortedDictionary<int, List<int>>();
if (trees.Count < 2) { return trees; } // dont process if ntrees contains 1 or 0 trees
foreach (KeyValuePair<int, List<int>> singletree in trees)
{
int cursor = 1;
bool nFinish = false;
List<int> n = singletree.Value;
if (n.Count <= 1) continue;
while (nFinish == false)
{
if (trees.ContainsKey(n[cursor]))
{
List<int> t = trees[n[cursor]]; // think of a screen cursor going over the list table
t.AddRange(n);
trees.Remove(n[cursor]);
n.Sort();
trees[singletree.Key] = n;
}
cursor++;
if (cursor != n.Count) continue;
nFinish = true;
}
}
return trees;
}
Well i decreased the size of the function and improved it.
It should now be a single irritation over all trees.
Unless someone knows a better answer, i think its "the" answer.
The code has been tested to work with larger sets, and i couldnt spot errors.
static SortedDictionary<int, List<int>> NewSort(SortedDictionary<int, List<int>> trees)
{
bool debugmode = false;
//pre sort
List<int> indexTree = new List<int>();
foreach (KeyValuePair<int, List<int>> tree in trees)
{
indexTree.Add(tree.Key);
if(debugmode) Console.WriteLine("* " +DumpIntList(trees[tree.Key]));
}
for (int i = (indexTree.Count); i > 0; i--)
{
if (debugmode) Console.WriteLine(i.ToString());
List<int> tree = new List<int>();
tree = trees[indexTree[i-1]];
for (int j = 0; j < tree.Count; j++)
{
int c = tree[j];
for (int k = (i - 2); k > -1; k--) // k can be 0 but i can minimally be 1
{
List<int> compareTree = new List<int>();
compareTree = trees[indexTree[k]]; // for loop > checking all trees
if (compareTree.IndexOf(c) != -1) // found !
{
if (debugmode) Console.Write("found " + c.ToString() + " from ");
if (debugmode) Console.WriteLine(DumpIntList(tree) + " in (" + DumpIntList(compareTree)+ ")");
// tree.Remove(c); // or we would create a duplicate
compareTree.AddRange(tree);
compareTree = compareTree.Distinct().ToList();
compareTree.Sort();
trees.Remove(indexTree[i - 1]);
trees[indexTree[k]] = compareTree;
j =tree.Count; //break from more checks. maybe dirty code but it increases speed
break; //break checking loop on all trees for current tree
}
}
}
}
return trees;
}
Here is your solution with test cases
using System;
using System.Collections.Generic;
using System.Linq;
namespace Demo
{
public class Example
{
public static void Main()
{
SortedDictionary<int, List<int>> tempRepositary = new SortedDictionary<int, List<int>>();
//test 1
tempRepositary.Add(2, new List<int>(new[] { 2, 3, 5, 6, 7 }));
tempRepositary.Add(5, new List<int>(new[] { 5, 7, 9 }));
tempRepositary.Add(11, new List<int>(new[] { 11, 12, 12, 27, 30, 31 }));
tempRepositary.Add(22, new List<int>(new[] { 22, 27 }));
tempRepositary.Add(23, new List<int>(new[] { 23, 25 }));
tempRepositary.Add(28, new List<int>(new[] { 28, 30 }));
tempRepositary.Add(34, new List<int>(new[] { 34 }));
//test 2
//tempRepositary.Add(2, new List<int>(new[] { 2,3,6,7 }));
//tempRepositary.Add(3, new List<int>(new[] { 3,5 }));
//tempRepositary.Add(5, new List<int>(new[] { 5,7,9 }));
//tempRepositary.Add(11, new List<int>(new[] { 11,12,12 }));
var refreshOne = SortTree(tempRepositary);
foreach (var item in refreshOne)
{
Console.Write("Key:" + item.Key + " ");
Console.WriteLine(string.Join(",", item.Value));
}
Console.ReadKey();
}
private static SortedDictionary<int, List<int>> SortTree(SortedDictionary<int, List<int>> trees)
{
if (trees.Count < 2) { return trees; } // dont process if ntrees contains 1 or 0 trees
SortedDictionary<int, List<int>> compressedTree
= new SortedDictionary<int, List<int>>();
var allKeys = trees.Keys.ToList();
var allValues = trees.Values.ToList();
for (int i = 0; i < allKeys.Count; i++)
{
var tempValues = allValues[i];
var tempMax = tempValues.Max();
for (int j = i + 1; j < allKeys.Count; )
{
if (tempMax >= allKeys[j])
{
tempValues.AddRange(allValues[j]);
allKeys.Remove(allKeys[j]);
allValues.Remove(allValues[j]);
//
tempMax = tempValues.Max();
continue;
}
j++;
}
compressedTree.Add(allKeys[i], tempValues.Distinct().OrderBy(i1 => i1).ToList());
}
return compressedTree;
}
}
}
So there's this blog that gives Five programming problems every Software Engineer should be able to solve in less than 1 hour and I'm just revisiting some of the concepts.
The first question reads
Write three functions that compute the sum of the numbers in a given list using a for-loop, a while-loop, and recursion.
Obviously the for- and while-loops are easy, but i started out with
int[] l = { 1, 2, 3, 4, 5, 6, 7, 8, 9};
Is it at all possible to pop an item off the list and then pass the shortened list every time?
An attempt I saw in python:
numbers = [1,2,3,4,5,6,7,8,9]
def recurse_count(lst):
if len(lst) == 1:
return lst[0]
else:
i = len(lst) - 1
subtotal = lst[i] + lst[i - 1]
lst.pop() #into the void with you
lst[-1] = subtotal
return recurse_count(lst)
Would it be possible with a int[] in c# ?
A very elegant solution would be:
static public int sumThisUp(IEnumerable<int> list)
{
return list.FirstOrDefault() + (list.Any() ? sumThisUp(list.Skip(1)) : 0);
}
Yes. I do belive the List-class has a simple removeAt(int)-method. A recursive method would look like this:
public int sumThisUp(List<int> list) {
int result = list[0];
list.removeAt(0);
return (list.length > 0) ? result + sumThisUp(list) : result;
}
Alternatively if you dont wanna edit the orginal list this would do:
public int sumThisUp2(List<int> list, int index = 0) {
int result = list[index++];
return (list.Count > index) ? result + sumThisUp2(list, index) : result;
}
Yes, it is possible in C#.
But I want to introduce some trick first: instead of modifying the source list we can just pass the start index. It will be much faster:
private static int Sum(int[] array, int startIndex)
{
if (startIndex >= array.Length)
{
return 0;
}
return array[startIndex] + Sum(array, startIndex + 1);
}
static void Main(string[] args)
{
int[] array = new int[] { 1, 2, 3, 4 };
int result = Sum(array, 0);
Console.WriteLine(result);
}
This should do it:
public int Sum(int[] numbers, int startAt = 0)
{
if (startAt == numbers.Length)
return 0;
return numbers[startAt] + Sum(numbers, startAt + 1);
}
I have been stumped on this one for a while. I want to take a List and order the list such that the Products with the largest Price end up in the middle of the list. And I also want to do the opposite, i.e. make sure that the items with the largest price end up on the outer boundaries of the list.
Imagine a data structure like this.. 1,2,3,4,5,6,7,8,9,10
In the first scenario I need to get back 1,3,5,7,9,10,8,6,4,2
In the second scenario I need to get back 10,8,6,4,2,1,3,5,7,9
The list may have upwards of 250 items, the numbers will not be evenly distributed, and they will not be sequential, and I wanted to minimize copying. The numbers will be contained in Product objects, and not simple primitive integers.
Is there a simple solution that I am not seeing?
Any thoughts.
So for those of you wondering what I am up to, I am ordering items based on calculated font size. Here is the code that I went with...
The Implementation...
private void Reorder()
{
var tempList = new LinkedList<DisplayTag>();
bool even = true;
foreach (var tag in this) {
if (even)
tempList.AddLast(tag);
else
tempList.AddFirst(tag);
even = !even;
}
this.Clear();
this.AddRange(tempList);
}
The Test...
[TestCase(DisplayTagOrder.SmallestToLargest, Result=new[]{10,14,18,22,26,30})]
[TestCase(DisplayTagOrder.LargestToSmallest, Result=new[]{30,26,22,18,14,10})]
[TestCase(DisplayTagOrder.LargestInTheMiddle, Result = new[] { 10, 18, 26, 30, 22, 14 })]
[TestCase(DisplayTagOrder.LargestOnTheEnds, Result = new[] { 30, 22, 14, 10, 18, 26 })]
public int[] CalculateFontSize_Orders_Tags_Appropriately(DisplayTagOrder sortOrder)
{
list.CloudOrder = sortOrder;
list.CalculateFontSize();
var result = (from displayTag in list select displayTag.FontSize).ToArray();
return result;
}
The Usage...
public void CalculateFontSize()
{
GetMaximumRange();
GetMinimunRange();
CalculateDelta();
this.ForEach((displayTag) => CalculateFontSize(displayTag));
OrderByFontSize();
}
private void OrderByFontSize()
{
switch (CloudOrder) {
case DisplayTagOrder.SmallestToLargest:
this.Sort((arg1, arg2) => arg1.FontSize.CompareTo(arg2.FontSize));
break;
case DisplayTagOrder.LargestToSmallest:
this.Sort(new LargestFirstComparer());
break;
case DisplayTagOrder.LargestInTheMiddle:
this.Sort(new LargestFirstComparer());
Reorder();
break;
case DisplayTagOrder.LargestOnTheEnds:
this.Sort();
Reorder();
break;
}
}
The appropriate data structure is a LinkedList because it allows you to efficiently add to either end:
LinkedList<int> result = new LinkedList<int>();
int[] array = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
Array.Sort(array);
bool odd = true;
foreach (var x in array)
{
if (odd)
result.AddLast(x);
else
result.AddFirst(x);
odd = !odd;
}
foreach (int item in result)
Console.Write("{0} ", item);
No extra copying steps, no reversing steps, ... just a small overhead per node for storage.
C# Iterator version
(Very simple code to satisfy all conditions.)
One function to rule them all! Doesn't use intermediate storage collection (see yield keyword). Orders the large numbers either to the middle, or to the sides depending on the argument. It's implemented as a C# iterator
// Pass forward sorted array for large middle numbers,
// or reverse sorted array for large side numbers.
//
public static IEnumerable<long> CurveOrder(long[] nums) {
if (nums == null || nums.Length == 0)
yield break; // Nothing to do.
// Move forward every two.
for (int i = 0; i < nums.Length; i+=2)
yield return nums[i];
// Move backward every other two. Note: Length%2 makes sure we're on the correct offset.
for (int i = nums.Length-1 - nums.Length%2; i >= 0; i-=2)
yield return nums[i];
}
Example Usage
For example with array long[] nums = { 1,2,3,4,5,6,7,8,9,10,11 };
Start with forward sort order, to bump high numbers into the middle.
Array.Sort(nums); //forward sort
// Array argument will be: { 1,2,3,4,5,6,7,8,9,10,11 };
long[] arrLargeMiddle = CurveOrder(nums).ToArray();
Produces: 1 3 5 7 9 11 10 8 6 4 2
Or, Start with reverse sort order, to push high numbers to sides.
Array.Reverse(nums); //reverse sort
// Array argument will be: { 11,10,9,8,7,6,5,4,3,2,1 };
long[] arrLargeSides = CurveOrder(nums).ToArray();
Produces: 11 9 7 5 3 1 2 4 6 8 10
Significant namespaces are:
using System;
using System.Collections.Generic;
using System.Linq;
Note: The iterator leaves the decision up to the caller about whether or not to use intermediate storage. The caller might simply be issuing a foreach loop over the results instead.
Extension Method Option
Optionally change the static method header to use the this modifier public static IEnumerable<long> CurveOrder(this long[] nums) { and put it inside a static class in your namespace;
Then call the order method directly on any long[ ] array instance like so:
Array.Reverse(nums); //reverse sort
// Array argument will be: { 11,10,9,8,7,6,5,4,3,2,1 };
long[] arrLargeSides = nums.CurveOrder().ToArray();
Just some (unneeded) syntactic sugar to mix things up a bit for fun. This can be applied to any answers to your question that take an array argument.
I might go for something like this
static T[] SortFromMiddleOut<T, U>(IList<T> list, Func<T, U> orderSelector, bool largestInside) where U : IComparable<U>
{
T[] sortedArray = new T[list.Count];
bool add = false;
int index = (list.Count / 2);
int iterations = 0;
IOrderedEnumerable<T> orderedList;
if (largestInside)
orderedList = list.OrderByDescending(orderSelector);
else
orderedList = list.OrderBy(orderSelector);
foreach (T item in orderedList)
{
sortedArray[index] = item;
if (add)
index += ++iterations;
else
index -= ++iterations;
add = !add;
}
return sortedArray;
}
Sample invocations:
int[] array = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int[] sortedArray = SortFromMiddleOut(array, i => i, false);
foreach (int item in sortedArray)
Console.Write("{0} ", item);
Console.Write("\n");
sortedArray = SortFromMiddleOut(array, i => i, true);
foreach (int item in sortedArray)
Console.Write("{0} ", item);
With it being generic, it could be a list of Foo and the order selector could be f => f.Name or whatever you want to throw at it.
The fastest (but not the clearest) solution is probably to simply calculate the new index for each element:
Array.Sort(array);
int length = array.Length;
int middle = length / 2;
int[] result2 = new int[length];
for (int i = 0; i < array.Length; i++)
{
result2[middle + (1 - 2 * (i % 2)) * ((i + 1) / 2)] = array[i];
}
Something like this?
public IEnumerable<int> SortToMiddle(IEnumerable<int> input)
{
var sorted = new List<int>(input);
sorted.Sort();
var firstHalf = new List<int>();
var secondHalf = new List<int>();
var sendToFirst = true;
foreach (var current in sorted)
{
if (sendToFirst)
{
firstHalf.Add(current);
}
else
{
secondHalf.Add(current);
}
sendToFirst = !sendToFirst;
}
//to get the highest values on the outside just reverse
//the first list instead of the second
secondHalf.Reverse();
return firstHalf.Concat(secondHalf);
}
For your specific (general) case (assuming unique keys):
public static IEnumerable<T> SortToMiddle<T, TU>(IEnumerable<T> input, Func<T, TU> getSortKey)
{
var sorted = new List<TU>(input.Select(getSortKey));
sorted.Sort();
var firstHalf = new List<TU>();
var secondHalf = new List<TU>();
var sendToFirst = true;
foreach (var current in sorted)
{
if (sendToFirst)
{
firstHalf.Add(current);
}
else
{
secondHalf.Add(current);
}
sendToFirst = !sendToFirst;
}
//to get the highest values on the outside just reverse
//the first list instead of the second
secondHalf.Reverse();
sorted = new List<TU>(firstHalf.Concat(secondHalf));
//This assumes the sort keys are unique - if not, the implementation
//needs to use a SortedList<TU, T>
return sorted.Select(s => input.First(t => s.Equals(getSortKey(t))));
}
And assuming non-unique keys:
public static IEnumerable<T> SortToMiddle<T, TU>(IEnumerable<T> input, Func<T, TU> getSortKey)
{
var sendToFirst = true;
var sorted = new SortedList<TU, T>(input.ToDictionary(getSortKey, t => t));
var firstHalf = new SortedList<TU, T>();
var secondHalf = new SortedList<TU, T>();
foreach (var current in sorted)
{
if (sendToFirst)
{
firstHalf.Add(current.Key, current.Value);
}
else
{
secondHalf.Add(current.Key, current.Value);
}
sendToFirst = !sendToFirst;
}
//to get the highest values on the outside just reverse
//the first list instead of the second
secondHalf.Reverse();
return(firstHalf.Concat(secondHalf)).Select(kvp => kvp.Value);
}
Simplest solution - order the list descending, create two new lists, into the first place every odd-indexed item, into the other every even indexed item. Reverse the first list then append the second to the first.
Okay, I'm not going to question your sanity here since I'm sure you wouldn't be asking the question if there weren't a good reason :-)
Here's how I'd approach it. Create a sorted list, then simply create another list by processing the keys in order, alternately inserting before and appending, something like:
sortedlist = list.sort (descending)
biginmiddle = new list()
state = append
foreach item in sortedlist:
if state == append:
biginmiddle.append (item)
state = prepend
else:
biginmiddle.insert (0, item)
state = append
This will give you a list where the big items are in the middle. Other items will fan out from the middle (in alternating directions) as needed:
1, 3, 5, 7, 9, 10, 8, 6, 4, 2
To get a list where the larger elements are at the ends, just replace the initial sort with an ascending one.
The sorted and final lists can just be pointers to the actual items (since you state they're not simple integers) - this will minimise both extra storage requirements and copying.
Maybe its not the best solution, but here's a nifty way...
Let Product[] parr be your array.
Disclaimer It's java, my C# is rusty.
Untested code, but you get the idea.
int plen = parr.length
int [] indices = new int[plen];
for(int i = 0; i < (plen/2); i ++)
indices[i] = 2*i + 1; // Line1
for(int i = (plen/2); i < plen; i++)
indices[i] = 2*(plen-i); // Line2
for(int i = 0; i < plen; i++)
{
if(i != indices[i])
swap(parr[i], parr[indices[i]]);
}
The second case, Something like this?
int plen = parr.length
int [] indices = new int[plen];
for(int i = 0; i <= (plen/2); i ++)
indices[i] = (plen^1) - 2*i;
for(int i = 0; i < (plen/2); i++)
indices[i+(plen/2)+1] = 2*i + 1;
for(int i = 0; i < plen; i++)
{
if(i != indices[i])
swap(parr[i], parr[indices[i]]);
}