Converting nested for loops with a depth of n - c#

I've been trying to build a recursive function to replace the following n deep nested loop algorithm, the depth will change based on the length of the combination anywhere for 2 to n (most likely less than 20)
Edit: removed confusing code
I have searched this site and found Converting nested loop and More nested loop conversions but I can't seam to tweak them to output what I need.
or I could just be looking at it wrong and not needing a recursive function at all.
trying to do this in C#, thanks for any help.
Edit: hope this explains things a bit more.
What I’m trying to do is find the best combination of options and amounts to give me maximum return without going over budget.
So I have a cut down list of options that meets my requirements, then I want to feed them into this program/script to get the best combination with highset return, I also need to reduce my risk by buying more than one option normally 3-10
So below is my full code so far fixed at a depth of 3:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Combinations
{
class Program
{
static void Main(string[] args)
{
Stopwatch stopwatch = new Stopwatch();
List<option> options = new List<option> {
new option("A", 6.50, 0.18, 25000, 3),
new option("B", 23.00, 0.59, 25000, 3),
new option("C", 27.50, 0.60, 25000, 3),
new option("D", 21.00, 0.40, 25000, 3),
new option("E", 16.00, 0.30, 25000, 3),
new option("F", 7.00, 0.13, 25000, 3),
new option("G", 22.50, 0.38, 25000, 3),
new option("H", 27.00, 0.45, 25000, 3),
new option("I", 13.00, 0.20, 25000, 3),
new option("J", 20.50, 0.30, 25000, 3),
new option("K", 17.50, 0.25, 25000, 3),
new option("L", 10.50, 0.15, 25000, 3),
new option("M", 29.00, 0.41, 25000, 3),
new option("N", 26.50, 0.37, 25000, 3),
new option("P", 15.50, 0.21, 25000, 3),
new option("Q", 16.00, 0.20, 25000, 3),
new option("R", 10.00, 0.12, 25000, 3),
new option("S", 25.00, 0.30, 25000, 3),
new option("T", 27.00, 0.32, 25000, 3),
new option("U", 22.00, 0.25, 25000, 3),
new option("V", 26.50, 0.30, 25000, 3),
new option("W", 27.00, 0.30, 25000, 3),
new option("X", 14.50, 0.16, 25000, 3),
new option("Y", 28.50, 0.31, 25000, 3),
new option("Z", 28.50, 0.30, 25000, 3)
};
stopwatch.Start();
IEnumerable<List<option>> combinations = GetCombination(options, 3);
stopwatch.Stop();
Console.WriteLine("Combinations - Time elapsed: {0}", stopwatch.Elapsed);
stopwatch.Start();
bestFit(combinations);
stopwatch.Stop();
Console.WriteLine("Best Fit - Time elapsed: {0}", stopwatch.Elapsed);
Console.ReadKey();
}
static IEnumerable<List<option>> GetCombination(List<option> list, int _size)
{
double count = Math.Pow(2, list.Count);
List<option> combination = new List<option>();
int size = 0;
for (int i = 1; i <= count - 1; i++)
{
for (int j = 0; j < list.Count; j++)
{
if (((i >> j) & 1) == 1)
{
combination.Add(list[j]);
size++;
}
}
if (size == _size)
{
yield return combination;
}
combination.Clear();
size = 0;
}
}
static void bestFit(IEnumerable<List<option>> combinations)
{
double max = 0d;
double results = 0d;
double total = 0d;
string output = "";
string tmpOutput = "";
int y0 = 0;
int y1 = 1;
int yn = 2;
foreach (var combination in combinations)
{
option A1 = combination[y0];
for (int x1 = A1.lower; x1 < A1.upper; x1++)
{
option A2 = combination[y1];
for (int x2 = A2.lower; x2 < A2.upper; x2++)
{
option An = combination[yn];
for (int xn = An.lower; xn < An.upper; xn++)
{
int[] counts = { x1, x2, xn };
int i = 0;
foreach (option objOption in combination)
{
results += objOption.bid * 100 * counts[i] / objOption.cash;
total += (objOption.strike - objOption.bid) * 100 * counts[i];
tmpOutput += objOption.symbol + " STO " + counts[i].ToString() + " # $" + objOption.strike + ", ";
i++;
}
if (results > max && total < A1.cash)
{
output = tmpOutput.Remove(tmpOutput.Length - 2) + " for a gain of " + results*100 + "% using a total of $" + total;
max = results;
}
results = 0d;
total = 0d;
tmpOutput = "";
}
}
}
}
Console.WriteLine(output);
}
}
class option
{
public string symbol { get; set; }
public double strike { get; set; }
public double bid { get; set; }
public double cash { get; set; }
public int lower;
public int upper;
public option(string _symbol, double _strike, double _bid, double _cash, int _trades)
{
this.symbol = _symbol;
this.strike = _strike;
this.bid = _bid;
this.cash = _cash;
double tradeCash = _cash / _trades;
this.lower = (int)((0.25 * tradeCash) / ((_strike - _bid) * 100));
this.upper = (int)((1.25 * tradeCash) / ((_strike - _bid) * 100));
}
}
}
This should give an output of:
Combinations - Time elapsed: 00:00:00.0002575
A STO 15 # $6.5, B STO 3 # $23, D STO 4 # $21 for a gain of 2.428% using a total of $24443
Best Fit - Time elapsed: 00:00:11.9196411
hope this help to clear things up.

it seems as if you are only using the for loops to produce your count entry. I would first begin by refactoring this part out into something like this:
public struct Bound
{
public int Lower { get; set; }
public int Upper { get; set; }
}
public static class Counting
{
public static IEnumerable<int[]> Indizes(this Bound[] bounds)
{
return Indizes(bounds, 0);
}
static IEnumerable<int[]> Indizes(this Bound[] bounds, int index)
{
if (index >= bounds.Length)
yield return new int[] {};
else
{
foreach(var comb in Indizes(bounds, index+1))
{
for (var i = bounds[index].Lower; i < bounds[index].Upper; i++)
{
var newArr = new int[comb.Length + 1];
Array.Copy(comb, 0, newArr, 1, comb.Length);
newArr[0] = i;
yield return newArr;
}
}
}
}
}
remark mostlikely you can get this faster but I think it shows you how you can do such thinks using recursion
With something like this (replace the Bound struct with your data-structure - it's only in there so I could test my code) your insane-loop simplifies to:
foreach(var combination in combinations)
{
foreach (var counts in Counting.Indizes(combination))
{
int i = 0;
foreach (myClass objMyClass in combination)
{
results += objMyClass.a * 100 * counts[i] / objMyClass.b;
total += (objMyClass.c - objMyClass.a) * 100 * counts[i];
tmpOutput += objMyClass.symbol + " count " + counts[i].ToString() + ", ";
i++;
}
// ...
}
}
for the rest I don't understand your code enough to give any advice

Related

Average of List<objects> in c#

I have a list of object.
class Student
{
int age;
int height;
int weight;
int marksInMath;
int marksInScience;
.
.
.
.
.
.
int marksIn...;
}
List<Student> lst = new List<Student>();
I want to calculate median and average of this List.
I am aware of
lst.Average(x=>x.Age);
lst.Average(x=>x.height);
.
.
Similarly for Median I can sort and then get median
lst.OrderBy(x=>x.Age);
//median logic on lst
But I don't want to repeat this code for every field(age, height, weight, marks, etc) in the object. Is there a way to do this in a loop or any other way so I don't have to get average for each field individually?
Here's the one pass way to compute averages:
var averages =
lst
.Aggregate(
new
{
N = 0,
Age = 0,
Height = 0,
Weight = 0,
MarksInMath = 0,
MarksInScience = 0
},
(a, x) =>
new
{
N = a.N + 1,
Age = a.Age + x.Age,
Height = a.Height + x.Height,
Weight = a.Weight + x.Weight,
MarksInMath = a.MarksInMath + x.MarksInMath,
MarksInScience = a.MarksInScience + x.MarksInScience,
},
a =>
new
{
Age = (double)a.Age / a.N,
Height = (double)a.Height / a.N,
Weight = (double)a.Weight / a.N,
MarksInMath = (double)a.MarksInMath / a.N,
MarksInScience = (double)a.MarksInScience / a.N,
});
If you're after sums, stddev, etc, it's done the same way.
However, you're not going to be able compute the median without doing so on each property, one at a time.
I am at work so haven't been able to run this to see if it works. But if you can retrieve the values of each field using Student.fieldName then should be good. Not 100% on the studentStats.Add, whether that's how to add it or not. Just know I've done it before without needing the Tuple.
public List<(decimal avg, decimal med)> StudentScores(List<Student> students)
{
var fieldNames = typeof(Student).GetFields().Select(field=>field.Name).ToList();
var studentStats = new List<(decimal avg, decimal med)>();
foreach(var field in fieldNames)
{
var average = 0;
var count = 0;
List<decimal> fieldMedian = new List<decimal>();
foreach(var student in students)
{
count++
totalScore = average + student.field;
fieldMedian.Add(student.field);
}
average = totalScore / count;
var sorted = fieldMedian.Sort();
if(count%2 = 0)
{
var middle1 = count/2;
var middle2 = (count/2)+1;
var median = (sorted[middle1] + sorted[middle2]) / 2;
studentStats.Add(average, median);
}
else
{
var middle = (count+1)/2;
var median = sorted[middle];
studentStats.Add(average, median);
}
}
return studentStats;
}

Ensure prize pool doesn't award tied participants less than participants who scored worse [duplicate]

This question already has answers here:
Divide x into y parts by decreasing amount
(3 answers)
Closed 3 years ago.
If I had $1000(variable) and I want to split that amount up and give it to 20(variable) people, but rather than give it evenly to each person, I want to give more to the 1st person, and the 2nd person, etc.
So the 20th person gets the least, and the 5th person gets the 5th most.
People are sorted into a list by score, how could i check to make sure people with the same score are awarded the same amount of the prize while still giving out the prize total to all people?
Formula thus far:
int people = 20;
float prize = 1000;
List<int> list = new List<int>();
for( int i = 0; i < people; ++i )
{
list.add(Random.Range(0,100));
}
list.Sort();
float k = (2 * prize) / ((people) * (people - 1));
float sum = 0;
for (int i = 1; i < list.Count-1; ++i)
{
var personsPrize = i * k;
sum += personsPrize;
Console.WriteLine(personsPrize);
}
Console.WriteLine("sum = " + sum);
First place would get 25% of the total prize pool. Second place gets 20% and third place gets 15% then the rest is divided between the remaining people, with people on the same score getting the same amount.
What should happen for people getting tied first equal? They shouldn't get less than anybody else, but shouldn't double the first prize value.
I'd do it by splitting out the prize fractions first, and determining which prizes should be merged due to ties. Then, sum up the merged fractions and divide that merged amount equally to all the tied participants.
This ensures that the amount received for each tied participant is less than or equal to the greatest prize amount merged in and greater than or equal to the least prize amount merged in.
public class Person
{
public Person(string name, int position)
{
Name = name;
Position = position;
}
public string Name { get; set; }
public int Position { get; set; }
}
static void Main(string[] args)
{
var winners = new Person[]
{
new Person("Test 1", 1),
new Person("Test 2", 1),
new Person("Test 3", 1),
new Person("Test 4", 1),
new Person("Test 5", 5),
new Person("Test 6", 6),
new Person("Test 7", 7),
new Person("Test 8", 8),
new Person("Test 9", 9),
new Person("Test 10", 9),
new Person("Test 11", 11),
new Person("Test 12", 11),
new Person("Test 13", 13),
new Person("Test 14", 14),
new Person("Test 15", 15),
new Person("Test 16", 16),
new Person("Test 17", 17),
new Person("Test 18", 18),
new Person("Test 19", 19),
new Person("Test 20", 19)
};
var prizes = SplitPrizeFund(1000, winners.Length);
AllocatePrizes(winners, prizes);
}
private static void AllocatePrizes(IEnumerable<Person> positions, double[] prizes)
{
var orderedPositions = positions.OrderBy(f => f.Position).ToArray();
for (var pos = 0; pos < orderedPositions.Length;)
{
var currentPerson = orderedPositions[pos];
// Find equally placed people (if any)
var comList = orderedPositions.Skip(pos).Where(f => f.Position == currentPerson.Position).ToList();
// We should now have one or more people in our list
var splitWays = comList.Count;
// Total the prize fund over the places found
double splitFund = prizes.Skip(pos).Take(splitWays).Sum();
// Allocate the total winnings equally between winners of this place
bool first = true;
foreach (var person in comList)
{
if (first)
{
Console.WriteLine($"{person.Name,-20} {(splitFund / splitWays),10:C2}");
first = false;
}
else
{
// Identify equal placed winners
Console.WriteLine($"{person.Name,-19}= {(splitFund / splitWays),10:C2}");
}
}
pos += splitWays;
}
}
private static double[] SplitPrizeFund(double totalFund, int numberOfPrizes)
{
var prizes = new double[numberOfPrizes];
var remainingFund = totalFund;
int remainingPrizes = numberOfPrizes;
// Special handling for top three places
int pos = 0;
prizes[pos] = Math.Round(remainingFund * 0.25, 2, MidpointRounding.AwayFromZero);
pos += 1;
prizes[pos] = Math.Round(remainingFund * 0.20, 2, MidpointRounding.AwayFromZero);
pos += 1;
prizes[pos] = Math.Round(remainingFund * 0.15, 2, MidpointRounding.AwayFromZero);
pos += 1;
remainingPrizes -= 3;
remainingFund -= prizes[0] + prizes[1] + prizes[2];
// Linear reducing split from 4th (replace this with whatever you want)
int totalPortions = 0;
for (int i = 1; i <= remainingPrizes; i++)
totalPortions += i;
for (int i = remainingPrizes; i >= 1; i--)
{
prizes[pos] = Math.Round(remainingFund * i / totalPortions, 2, MidpointRounding.AwayFromZero);
remainingFund -= prizes[pos];
totalPortions -= i;
pos++;
}
return prizes;
}
This can be a solution :
class People
{
public int ID { get; set; }
public int Rank { get; set; }
public float? Prize { get; set; }
}
//Reserves 60% of the prize for the first, second and the third person.
//Imageine that there are 5 people have the highest rank 20 for exemple.
in this case the total of the first place makes 125%. It can't be possible.
For me, you should have another parameter to choose the first places.
Or, you should modify your rank logic: like if the total of percentages is over 100% or 90%, (or a percentage that you will decide), reduce the percentage of the first place, second and third places etc.
Imagene that you have 4 first place, 1 second place and 1 thirt place.
In this case you have (4 * 25%) + 20% + 15% = 135%. It means you have to reduce your 25% to for exemple 15 %, second place to 10% and the third place to 5%.
in this case you will have (4 * 15%) + 10% + 5% = 75 percent for your highest places and you will distribute 25% to other users.
private void CheckPrices()
{
float prize = 1000;
Random rnd = new Random(1);
var peopleList = new List<People>();
for (int i = 0; i < 20; i++)
{
peopleList.Add(new Test.People() { ID = i + 1, Rank = rnd.Next(5, 100) });
}
var firstPrize = prize * 25 / 100;
var secondPrize = prize * 20 / 100;
var thirstPrize = prize * 15 / 100;
int i = 0;
//Sets first places prizes.
foreach (var person in peopleList.OrderByDescending(ro => ro.Rank))
{
i++;
if (i == 1)
person.Prize = firstPrize;
else if (i == 2)
person.Prize = secondPrize;
else if (i == 3)
person.Prize = thirstPrize;
else
break;
}
var totalRank = peopleList.Sum(ro => ro.Rank);
float prizePerRank = (prize - (firstPrize + secondPrize + thirstPrize)) / totalRank;
foreach (var person in peopleList.Where( ro=> ro.Prize == null))
{
person.Prize = person.Rank * prizePerRank;
}
//
var totalPrizeDistributed = peopleList.Sum(ro => ro.Prize); //= 1000
}
}

K closest points to origin (K smallest elements) with hoare's partitioning not giving the correct answer for a specific input

I am solving this question: https://leetcode.com/problems/k-closest-points-to-origin/
In brief, given a list of points return the K closest to origin where the order within the K does not matter. I am trying to solve this with the quickselect variant using Hoare's partitioning, but for a specific inpput it does not give the right answer and I am unable to figure out why. The Hoare's partitioning logic itself is copied from wikipedia.
Points: [[68,97],[34,-84],[60,100],[2,31],[-27,-38],[-73,-74],[-55,-39],[62,91],[62,92],[-57,-67]]
K:5
namespace N
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
public class Solution
{
private readonly Random rand = new Random();
public int[][] KClosest(int[][] points, int K)
{
var result = new List<int[]>();
KClosestHelper(points, 0, points.Count() - 1, K);
return points.Take(K).ToArray();
}
private void KClosestHelper(int[][] points,
int left,
int right,
int k)
{
if (left >= right) return;
var partitionIndex = Partition(points, left, right);
int leftLength = partitionIndex - left + 1;
if (k < leftLength)
{
KClosestHelper(points, left, partitionIndex - 1, k);
}
else if (k > leftLength)
{
KClosestHelper(points, partitionIndex + 1, right, k - leftLength);
}
}
private int Partition(int[][] arr, int left, int right)
{
//var randomIndex = rand.Next(left, right+1);
//swap(arr, left, randomIndex);
var pivot = arr[left];
left--;
right++;
while (true)
{
do
{
left++;
} while (AIsCloserThanB(arr[left], pivot));
do
{
right--;
} while (AIsFartherThanB(arr[right], pivot));
if (left >= right) return right;
swap(arr, left, right);
}
}
private bool AIsCloserThanB(int[] a, int[] b)
{
return a[0] * a[0] - b[0] * b[0] + a[1] * a[1] - b[1] * b[1] < 0;
}
private bool AIsFartherThanB(int[] a, int[] b)
{
return a[0] * a[0] - b[0] * b[0] + a[1] * a[1] - b[1] * b[1] > 0;
}
private void swap(int[][] arr, int i, int j)
{
var temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
public class MainClass
{
public static void Main()
{
var arr = new int[10][];
arr[0] = new[] { 68, 97 };
arr[1] = new[] { 34, -84 };
arr[2] = new[] { 60, 100 };
arr[3] = new[] { 2, 31 };
arr[4] = new[] { -27, -38 };
arr[5] = new[] { -73, -74 };
arr[6] = new[] { -55, -39 };
arr[7] = new[] { 62, 91 };
arr[8] = new[] { 62, 92 };
arr[9] = new[] { -57, -67 };
var s = new Solution();
var closest = s.KClosest(arr, 5);
foreach (var item in closest)
{
Console.Out.WriteLine(string.Join(",", item));
}
}
}
}
While debugging in the Partition call with left ==3 and right ==7, 3 and 7 get swapped first (so now left is 3 and right is 7). Then left goes all the way to 7, and because of the do while right becomes 6 which is returned as the partition. But this is incorrect since points[5] is [-73,74] and points[6] is [-57,67] (so points[5] > points[6]). I think 7 should have been returned as a partition. This results in the final solution containing [-73,-74] instead of [-57,67]. Can someone please help me understand what part of the algorithm is incorrect/ not applicable to this problem since the wikipedia logic must be correct?
Define Point class
public class Point
{
public int X;
public int Y;
}
now put your points into Point[] points and execute simple linq query
var closest = points.OrderBy(p => p.X * p.X + p.Y * p.Y).Take(k);
Latest version of .NET are smart enough to use a QuickSelect if you don't need a full sorted collection, so expected complexity should be O(k log N)
don't know why the outcome but since this is c# why don't you simplify the code.
define the method returning the distance
private static double DistanceToCenter(int[] p)
{
return Math.Sqrt(p[0] ^ 2 + p[1] ^ 2);
}
then use linq:
var s = arr.OrderBy(p => DistanceToCenter(p));
this would give you the list sorted by the distance to 0.0, then select the k first to print out.

Logic in Change Conversion Program | indexOutOfRange [duplicate]

This question already has answers here:
What is an IndexOutOfRangeException / ArgumentOutOfRangeException and how do I fix it?
(5 answers)
Closed 5 years ago.
I'm working on a program for my C# class that is supposed to take an entered amount, as a double or not, and to find change in dollars, quarters, etc.,
I'm using the Greedy Algorithm, and I keep getting some sort of error that reads, "An unhandled exception of type 'System.IndexOutOfRangeException' occurred in 2D.exe".
I'm still relatively new to C#, and come from a Java and C++ Background.
So far I have my Money class:
using System;
using static System.Console;
namespace _2D
{
class Money
{
private double dollars, cents;
public void IncrementMoney() { }
public void DecrementMoney() { }
public Money(double dollarsncents)
{
double amountLeftOfDecimal = Math.Truncate(dollarsncents);
double amountRightOfDecimal = Math.Floor(dollarsncents);
this.dollars = Math.Round(amountLeftOfDecimal);
//the following LOGIC needs to be wokred out:
this.cents = Math.Round((amountRightOfDecimal * 100) / 100, 2);
}
public Money(int ddollars, int ccents)
{
this.dollars = ddollars;
this.cents = ccents;
}
public override string ToString()
{
return String.Format(dollars + " dollars and " + cents + " cents.");
}
public void CoinAmounts(int inAmount, int remainder, int[] coins)
{
if((inAmount % 0.25) < inAmount)
{
coins[3] = (int)(inAmount / 0.25);
remainder = inAmount % (1/4);
inAmount = remainder;
}
if ((inAmount % 0.1) < inAmount)
{
coins[2] = (int)(inAmount / 0.1);
remainder = inAmount % (1/10);
inAmount = remainder;
}
if ((inAmount % 0.05) < inAmount)
{
coins[1] = (int)(inAmount / 0.05);
remainder = inAmount % (1/20);
inAmount = remainder;
}
if ((inAmount % 0.01) < inAmount)
{
coins[0] = (int)(inAmount / 0.01);
remainder = inAmount % (1/100);
}
}
public void PrintChange(int[] arr)
{
if (arr[3] > 0)
Console.WriteLine("Number of quarters: " + arr[3]);
if (arr[2] > 0)
Console.WriteLine("Number of dimes: " + arr[2]);
if (arr[1] > 0)
Console.WriteLine("Number of nickels: " + arr[1]);
if (arr[0] > 0)
Console.WriteLine("Number of pennies: " + arr[0]);
}
}
And my Main :
using System;
namespace _2D
{
class Program
{
static void Main(string[] args)
{
Money MyMoney = new Money(23, 24);
Console.WriteLine(MyMoney.ToString());
Money dollarCentAmount = new Money(12.45);
Console.WriteLine(dollarCentAmount.ToString());
Console.WriteLine("Press any key to continue.");
Console.ReadKey();
Console.Clear();
Console.WriteLine("Enter an amount you'd like change for: ");
double inAmountDouble = Convert.ToDouble(Console.ReadLine());
int inAmount = Convert.ToInt32(inAmountDouble);
int tochange = inAmount;
int remainder = 0;
int[] coins = new int[3];
MyMoney.CoinAmounts(inAmount, remainder, coins);
Console.WriteLine(" Change for " + inAmount + " is: ");
if (inAmount > 1.0)
{
Console.WriteLine("Number of dollars: " + Convert.ToInt32(inAmount));
}
MyMoney.PrintChange(coins);
Console.ReadKey();
}
}
}
You declared coins to be an array going from 0 to 2
array[size] //size is how many elements are in the array, not the upper bound of the array
coins[3] //means the array contains three elements, elements: 0, 1, 2
//so you want:
int[] coins = new int[4]; //Goes from 0 to 3, elements: 0, 1, 2, 3
//This will allow you to later access:
//since coins[3] is the 4th element, this is as high as the array can go now
coins[3] = (int)(inAmount / 0.25);

Code doesn't show correct product c#

I'm studying coding and I'm on project 8 of project euler.
I was able to show the product "5832" for four adjacent digits when I'm using my code however when I use it on 13 digits, it doesn't work. My code is:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace practice
{
class Program
{
static void Main(string[] args)
{
const string number = "7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450";
string input1, input2, input3, input4, input5;
string input6, input7, input8, input9, input10;
string input11, input12, input13;
int convert1, convert2, convert3, convert4, convert5;
int convert6, convert7, convert8, convert9, convert10;
int convert11, convert12, convert13;
convert1 = convert2 = convert3 = convert4 = convert5 = convert6 = convert7 = convert8 = 0;
convert9 = convert10 = convert11 = convert12 = convert13 = 0;
int counter;
int product = 0;
int largest = 0;
int length = number.Length - 13;
for (counter = 1; counter <= length; counter++)
{
input1 = number.Substring(counter, 1);
input2 = number.Substring(counter+1, 1);
input3 = number.Substring(counter+2, 1);
input4 = number.Substring(counter+3, 1);
input5 = number.Substring(counter+4, 1);
input6 = number.Substring(counter+5, 1);
input7 = number.Substring(counter+6, 1);
input8 = number.Substring(counter+7, 1);
input9 = number.Substring(counter+8, 1);
input10 = number.Substring(counter+9, 1);
input11 = number.Substring(counter+10, 1);
input12 = number.Substring(counter+11, 1);
input13 = number.Substring(counter+12, 1);
convert1 = Convert.ToInt32(input1);
convert2 = Convert.ToInt32(input2);
convert3 = Convert.ToInt32(input3);
convert4 = Convert.ToInt32(input4);
convert5 = Convert.ToInt32(input5);
convert6 = Convert.ToInt32(input6);
convert7 = Convert.ToInt32(input7);
convert8 = Convert.ToInt32(input8);
convert9 = Convert.ToInt32(input9);
convert10 = Convert.ToInt32(input10);
convert11 = Convert.ToInt32(input11);
convert12 = Convert.ToInt32(input12);
convert13 = Convert.ToInt32(input13);
product = convert1 * convert2 * convert3 * convert4 * convert5 * convert6
* convert7 * convert8 * convert9 * convert10 * convert11
* convert12 * convert13;
if (largest < product) { largest = product; }
}
Console.WriteLine("The largest number is {0}", largest);
Console.ReadKey();
}
}
}
It doesn't show the correct answer which I find daunting. The next steps
I did is:
1. Check the last 13 digits of my variables to check if it loops and multiplies correctly "0420420752963450".
2. Check if it works with the first four numbers and first five numbers which are surprisingly correct.
3. Studied how others have done it.
4. Links used:
Homework in Java. Find the largest product of five consecutive digits
http://www.mathblog.dk/solution-to-problem-8-of-project-euler/
I seem to not get it. Please guide me on seeing my mistake. Thank you.
Your product variable is int and you parse your consecutive numbers to int. Max value for integer is 2,147,483,647. So when you multiply 13 numbers it's quite possible you will exceed the limit and the value will overflow giving incorrect result. Perhaps, consider using BigInteger instead.
What about something like this:
[Test]
public void Test()
{
const string number = "7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450";
int index = 0;
int largest = 0;
var largestString = "";
const int length = 13;
while (index + length <= number.Length)
{
var substring = number.Substring(index, length);
var product = ProductOfEachNumber(substring);
if (product > largest)
{
largestString = substring;
largest = product;
}
index++;
}
Console.WriteLine("The largest number is {0}", largest);
Console.WriteLine("The largest number string is {0}", largestString);
}
[Test]
public void TestSubstring()
{
var res = ProductOfEachNumber("9989");
res.Should().Be(5832);
}
private static int ProductOfEachNumber(string substring)
{
return substring.Aggregate(1, (current, c) => current*Int32.Parse(c.ToString()));
}
Gives output:
The largest number is 2091059712
The largest number string is 9781797784617
Try this one, let me know. You have to modify it.
static void Main(string[] args)
{
Stopwatch sw = Stopwatch.StartNew();
int x = Largest();
Console.WriteLine(x);
Console.WriteLine("Time used (float): {0} ms", sw.Elapsed.TotalMilliseconds);
Console.WriteLine("Time used (rounded): {0} ms", sw.ElapsedMilliseconds);
Console.ReadKey();
}
public static int Largest()
{
string p = "7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450";
int largest = 0;
int numm = 0;
for (int i = 0; i < p.Length - 4; i++)
{
numm = int.Parse(p.Substring(i, 1)) *
int.Parse(p.Substring(i + 1, 1)) *
int.Parse(p.Substring(i + 2, 1)) *
int.Parse(p.Substring(i + 3, 1)) *
int.Parse(p.Substring(i + 4, 1));
if (numm > largest)
{
largest = numm;
}
}
return largest;
}

Categories