Index outside array inside loop - c#

I get an error Index was outside the bounds of the array, im trying to do some simple math and holding it in my list.
List<int> integerList = new List<int>();
for (int a = 0; a < textBox1.Text.Length; a++)
{
for (int b = 8; b > 1 ; b--)
{
integerList.Add(int.Parse(textBox1.Text[a * b].ToString())); //this line
}
}
listBox1.DataSource = integerList;
What I am trying to achieve is this, a user must enter a 7 digit number into the textbox say for instance 4565457, I wanted to store this number in my integerList, then take each number starting from the beginning of the users input and multiply down from 8 untill 2 is reached.
For instance:
4 x 8
5 x 7
6 x 6
5 x 5
4 x 4
5 x 3
7 x 2
I wanted to then store the sum of these multiplications for later use.

It's probably the textBox1.Text that's out of bounds. Try adding a check before using the indexer:
if (a*b < textBox1.Length)
integerList.Add(int.Parse(textBox1.Text[a * b].ToString())); //this line

Try this (since you probably want to calc the value of your a number by the value of b):
List<int> integerList = new List<int>();
for (int a = 0; a < textBox1.Text.Length; a++)
{
for (int b = 8; b > 1 ; b--)
{
integerList.Add(int.Parse(textBox1.Text[a].ToString()) * b); //this line
}
}
listBox1.DataSource = integerList;

The index a*b is outside the bounds of the TextBox content. You have to put in place safeguards to make sure you don't index the string content of the textbox using an index that is out of bounds

This line textBox1.Text[a * b] is likely the source of the problem. There's no bounds checking and a * b likely evaluates to an integer greater than the final index of textBox1. I don't have an great solution for you because I don't really understand what you're trying to do... The expression inside the inner for loop just generally does not make much sense.
You could simply check that a * b is less than textBox1.Text.Length in order to prevent the exception but that probably won't make the code do what you actually want it to.

Sorry didn't got time to read the edited question. According to new description, if user enters 4565457 you want to multiply each character in that string from position 0 to last (6 in this case) with 8 - position. Following loop single for loop will do the trick.
List<int> integerList = new List<int>();
var l = textBox1.Text.Length;
for (int a = 0, b = 8; a < l && b > 1; a++, b--)
{
integerList.Add((Convert.ToInt16(textBox1.Text[a]) * b)); //this line
}
listBox1.DataSource = integerList;
At the end of loop, listBox1 will contain following values:
416
371
324
265
208
159
110
Try this:
List<int> integerList = new List<int>();
var l = textBox1.Text.Length;
for (int a = 0; a < l; a++)
{
for (int b = 8; b > 1 && (a*b) < l ; b--)
{
integerList.Add(int.Parse(textBox1.Text[a * b].ToString())); //this line
}
}
listBox1.DataSource = integerList;
a * b is getting past the length of text in textbox so adding && (a*b) > l will keep this in control.

Related

C# WinsForm, Frequency Distribution Table [Updated]

Update 01
Thanks to Caius, found the main problem, the logic on the "if" was wrong, now fixed and giving the correct results. The loop still create more positions than needed on the secondary List, an extra position for each number on the main List.
I've updated the code bellow for refence for the following question:
-001 I can figure out why it create positions that needed, the for loop should run only after the foreach finishes its loops correct?
-002 To kind of solving this issue, I've used a List.Remove() to remove all the 0's, so far no crashes, but, the fact that I'm creating the extra indexes, and than removing them, does means a big performance down if I have large list of numbers? Or is an acceptable solution?
Description
It supposed to read all numbers in a central List1 (numberList), and count how many numbers are inside a certain (0|-15 / 15|-20) range, for that I use another List, that each range is a position on the List2 (numberSubList), where each number on List2, tells how many numbers exists inside that range.
-The range changes as the numbers grows or decrease
Code:
void Frequency()
{
int minNumb = numberList.Min();
int maxNumb = numberList.Max();
int size = numberList.Count();
numberSubList.Clear();
dGrdVFrequency.Rows.Clear();
dGrdVFrequency.Refresh();
double k = (1 + 3.3 * Math.Log10(size));
double h = (maxNumb - minNumb) / k;
lblH.Text = $"H: {Math.Round(h, 2)} / Rounded = {Math.Round(h / 5) * 5}";
lblK.Text = $"K: {Math.Round(k, 4)}";
if (h <= 5) { h = 5; }
else { h = Math.Round(h / 5) * 5; }
int counter = 1;
for (int i = 0; i < size; i++)
{
numberSubList.Add(0); // 001 HERE, creating more positions than needed, each per number.
foreach (int number in numberList)
{
if (number >= (h * i) + minNumb && number < (h * (i + 1)) + minNumb)
{
numberSubList[i] = counter++;
}
}
numberSubList.Remove(0); // 002-This to remove all the extra 0's that are created.
counter = 1;
}
txtBoxSubNum.Clear();
foreach (int number in numberSubList)
{
txtBoxSubNum.AppendText($"{number.ToString()} , ");
}
lblSubTotalIndex.Text = $"Total in List: {numberSubList.Count()}";
lblSubSumIndex.Text = $"Sum of List: {numberSubList.Sum()}";
int inc = 0;
int sum = 0;
foreach (int number in numberSubList)
{
sum = sum + number;
int n = dGrdVFrequency.Rows.Add();
dGrdVFrequency.Rows[n].Cells[0].Value = $"{(h * inc) + minNumb} |- {(h * (1 + inc)) + minNumb}";
dGrdVFrequency.Rows[n].Cells[1].Value = $"{number}";
dGrdVFrequency.Rows[n].Cells[2].Value = $"{sum}";
dGrdVFrequency.Rows[n].Cells[3].Value = $"{(number * 100) / size} %";
dGrdVFrequency.Rows[n].Cells[4].Value = $"{(sum * 100) / size} %";
inc++;
}
}
Screen shot showing the updated version.
I think, if your aim is to only store eg 17 in the "15 to 25" slot, this is wonky:
if (number <= (h * i) + minNumb) // Check if number is smaller than the range limit
Because it's found inside a loop that will move on to the next range, "25 to 35" and it only asks if the number 17 is less than the upper limit (and 17 is less than 35) so 17 is accorded to the 25-35 range too
FWIW the range a number should be in can be derived from the number, with (number - min) / number_of_ranges - at the moment you create your eg 10 ranges and then you visit each number 10 times looking to put it in a range, so you do 9 times more operations than you really need to

grahams scan to implement polygon partition in c#

I am trying to solve polygon partition problem using graham scan
below is the problem statement and input and expected output
I have implemented graham scan logic but i need to display output
according to the sets formed and display all the points with indexes;
The first line will contain a single integer ().
The next lines will contain two integers (), denoting a point with coordinates . Note that points are not guaranteed to be distinct.
SAMPLE INPUT
3
0 0
0 1
1 0
On the first line, output a single integer (), the number of sets in your partition.
On the next lines, print the elements of the partition. On the -th of these lines, first print the integer (), and then indices of points forming the -th set. Points are numbered starting from . Each index from to must appear in exactly one set.
SAMPLE OUTPUT
1
3 1 2 3
below is the code implemented according to the output mentioned above,
how to print for more sets?
private static void convexHull(Point[] points, int N, int set)
{
int index = 0;
List<int> result = new List<int>();
// There must be at least 3 points
if (N < 3) return;
// Initialize Result
MyStack<Point> hull = new MyStack<Point>(N);
// Find the leftmost point
int l = 0;
for (int i = 1; i < N; i++)
if (points[i].x < points[l].x)
l = i;
// Start from leftmost point, keep moving
// counterclockwise until reach the start point
// again. This loop runs O(h) times where h is
// number of points in result or output.
int p = l, q;
do
{
// Add current point to result
hull.push(points[p]);
// Search for a point 'q' such that
// orientation(p, x, q) is counterclockwise
// for all points 'x'. The idea is to keep
// track of last visited most counterclock-
// wise point in q. If any point 'i' is more
// counterclock-wise than q, then update q.
q = (p + 1) % N;
for (int i = 0; i < N; i++)
{
// If i is more counterclockwise than
// current q, then update q
if (orientation(points[p], points[i], points[q])
== 2)
q = i;
}
// Now q is the most counterclockwise with
// respect to p. Set p as q for next iteration,
// so that q is added to result 'hull'
p = q;
} while (p != l); // While we don't come to first
set += 1;
var ele = hull.GetAllStackElements();
foreach (Point pt in ele)
{
index += 1;
}
Console.WriteLine(set);
Console.Write(string.Format("{0} ", index));
for (int s = 1; s <= index; s++)
{
Console.Write(string.Format("{0} ", s));
}
Console.Write(Environment.NewLine);
}

Pick a varying number of item combinations from a List

Assume I have a list of integers of any length, for an example I have the list of 1,3,5 and 7.
I would like an algorithm to pick a combination of X elements from the list.
For example, X = 1 would return:
1
3
5
7
x = 2 would return:
1 + 1
1 + 3
1 + 5
1 + 7
3 + 3
3 + 5
3 + 7
5 + 5
5 + 7
7 + 7
var listOfInts = new List<int> { 1, 3, 5, 7 };
var combinedInts = new List<int>();
// x = 1 solution
// This is only picking one item from the list.
for (int i = 0; i < listOfInts.Count(); i++)
{
combinedInts.Add(listOfInts[i]);
}
// x = 2 solution
// This is how to pick two. I wrap it around another for loop.
for (int i = 0; i < listOfInts.Count(); i++)
{
for (int j = i; j < listOfInts.Count(); j++)
{
combinedInts.Add(listOfInts[i] + listOfInts[j]);
}
}
// x = 3 solution
// If I go up another level I have to wrap it around another for loop. This solution won't scale.
for (int i = 0; i < listOfInts.Count(); i++)
{
for (int j = i; j < listOfInts.Count(); j++)
{
for (int k = j; k < listOfInts.Count(); k++)
{
combinedInts.Add(listOfInts[i] + listOfInts[j] + listOfInts[k]);
}
}
}
This solution doesn't scale as I have to continually wrap around another for loop for each number of element I'm picking. For example X = 7 would need 7-nested for loops. Is there a better way to write this method that doesn't involve nesting for loops?
You can use the following to get combinations of the sequences:
public static class LinqHelper
{
public static IEnumerable<IEnumerable<T>> Combinations<T>(this IEnumerable<T> elements, int? k = null)
{
if (!k.HasValue)
k = elements.Count();
return k == 0 ? new[] { new T[0] } :
elements.SelectMany((e, i) => elements.Skip(i).Combinations(k - 1).Select(c => (new[] { e }).Concat(c)));
}
}
var list = new List<int> { 1, 3, 5, 7 };
int x = 2; //Change to 3, 4, 5, etc
var result = list.Combinations(x);
Yields:
1 1
1 3
1 5
1 7
3 3
3 5
3 7
5 7
7 7
To get the sum of each one, you'd aggregate the result:
var result = list.Combinations(x).Select(g => g.Aggregate((left, right) => left + right));
Which produces:
2
4
6
8
6
8
10
10
12
14
There is also a purely iterative way to do this. It requires a great deal more thought and complexity, but can be made very efficient. The basic idea is to simulate the same nested loops, but track the iterations of each nested loop as an array of loop counters, which are iterated forward in the same manner as the original nested loop code. Here is a fully working example:
var listOfInts = new List<int> { 1, 3, 5, 7 };
var combinedInts = new List<int>();
var numInts = listOfInts.Count;
var numElements = 5; // number of "nested loops", or ints selected in each combination
var loopCounters = new int[numElements]; // make one loop counter for each "nested loop"
var lastCounter = numElements - 1; // iterate the right-most counter by default
// maintain current sum in a variable for efficiency, since most of the time
// it is changing only by the value of one loop counter change.
var tempSum = listOfInts[0] * numElements;
// we are finished when the left/outer-most counter has looped past number of ints
while (loopCounters[0] < numInts) {
// you can use this to verify the output is iterating correctly:
// Console.WriteLine(string.Join(",", loopCounters.Select(x => listOfInts[x])) + ": " + loopCounters.Select(x => listOfInts[x]).Sum() + "; " + tempSum);
combinedInts.Add(tempSum);
tempSum -= listOfInts[loopCounters[lastCounter]];
loopCounters[lastCounter]++;
if (loopCounters[lastCounter] < numInts) tempSum += listOfInts[loopCounters[lastCounter]];
// if last element reached in inner-most counter, increment previous counter(s).
while (lastCounter > 0 && loopCounters[lastCounter] == numInts) {
lastCounter--;
tempSum -= listOfInts[loopCounters[lastCounter]];
loopCounters[lastCounter]++;
if (loopCounters[lastCounter] < numInts) tempSum += listOfInts[loopCounters[lastCounter]];
}
// if a previous counter was advanced, reset all future counters to same
// starting number to start iteration forward again.
while (lastCounter < numElements - 1) {
lastCounter++;
if (loopCounters[lastCounter] < numInts) tempSum -= listOfInts[loopCounters[lastCounter]];
loopCounters[lastCounter] = loopCounters[lastCounter - 1];
if (loopCounters[lastCounter] < numInts) tempSum += listOfInts[loopCounters[lastCounter]];
}
}
At the end of the iteration, combinedInts should contains a list of all sum combinations, similar to the original code or the other recursive solutions. If you are working with small sets, and small combinations, then this level of efficiency is unnecessary and you should prefer a recursive solution which is easier to reason about correctness. I present this as an alternative way to think about the problem. Cheers!
This works for me:
Func<IEnumerable<int>, int, IEnumerable<IEnumerable<int>>> generate = null;
generate = (xs, n) =>
(xs == null || !xs.Any())
? Enumerable.Empty<IEnumerable<int>>()
: n == 1
? xs.Select(x => new [] { x })
: xs.SelectMany(x => generate(xs, n - 1).Select(ys => ys.Concat(new [] { x })));
int[] array = { 1, 3, 5, 7, };
var results =
generate(array, 3)
.Select(xs => String.Join("+", xs));
With this call I get:
1+1+1, 3+1+1, 5+1+1, 7+1+1, 1+3+1, 3+3+1, 5+3+1, 7+3+1, 1+5+1, 3+5+1, 5+5+1, 7+5+1, 1+7+1, 3+7+1, 5+7+1, 7+7+1, 1+1+3, 3+1+3, 5+1+3, 7+1+3, 1+3+3, 3+3+3, 5+3+3, 7+3+3, 1+5+3, 3+5+3, 5+5+3, 7+5+3, 1+7+3, 3+7+3, 5+7+3, 7+7+3, 1+1+5, 3+1+5, 5+1+5, 7+1+5, 1+3+5, 3+3+5, 5+3+5, 7+3+5, 1+5+5, 3+5+5, 5+5+5, 7+5+5, 1+7+5, 3+7+5, 5+7+5, 7+7+5, 1+1+7, 3+1+7, 5+1+7, 7+1+7, 1+3+7, 3+3+7, 5+3+7, 7+3+7, 1+5+7, 3+5+7, 5+5+7, 7+5+7, 1+7+7, 3+7+7, 5+7+7,7+7+7

How to write groups of numbers using Console.Write?

I'm very new to C# (And Stack Overflow, forgive me for any poor etiquette here), and I'm writing the game Mastermind in a console application. I'm trying to show a list of the user's guesses at the end of the game, and I know that using Console.WriteLine(); will just give me 30-odd lines off numbers which don't tell the user anything.
How can I alter my code so that the program displays 4 numbers in a group, at a time? For example:
1234
1234
1234
//Store numbers in a history list
ArrayList guesses = new ArrayList(); //This is the ArrayList
Console.WriteLine("Please enter your first guess.");
guess1 = Convert.ToInt32(Console.ReadLine());
guesses.Add(guess1);
foreach (int i in guesses)
{
Console.Write(i);
}
I assume that each element of your byte array is a single digit (0-9). If that assumption is invalid -- please let me know, I'll modify the code :)
Action<IEnumerable<int>> dump = null;
dump = items =>
{
if(items.Any())
{
var head = String.Join("", items.Take(4));
Console.WriteLine(head);
var tail = items.Skip(4);
dump(tail);
}
};
dump(guesses);
It looks like you're most of the way there, you have a console write that writes them all out without linebreaks. Next add an integer count and set it to zero. Increment it by one in the foreach loop. count % 4 == 0 will then be true for all counts that are a multiple of four. This means you can stick an if block there with a write-line to give you your groups of four.
List<int> endResult = new List<int>();
StringBuilder tempSb = new StringBuilder();
for(int i=0; i < groups.Count; i++)
{
if(i % 4 == 0) {
endResult.Add(int.Parse(sb.ToString()));
tempSb.Clear(); // remove what was already added
}
tempSb.Append(group[i]);
}
// check to make sure there aren't any stragglers left in
// the StringBuilder. Would happen if the count of groups is not a multiple of 4
if(groups.Count % 4 != 0) {
groups.Add(int.Parse(sb.ToString()));
}
This will give you a list of 4 digit ints and make sure you don't lose any if your the number of ints in your groups list is not a multiple of 4. Please note that I am continuing based on what you provided, so groups is the ArrayList of ints.
This is some thing I quickly put together:
Update:
ArrayList guesses = new ArrayList(); //This is the ArrayList
// Four or more
guesses.Add(1); guesses.Add(2);
guesses.Add(3);guesses.Add(4);
guesses.Add(5); guesses.Add(6); guesses.Add(7);guesses.Add(8); guesses.Add(9);
//Uncomment-Me for less than four inputs
//guesses.Add(1); guesses.Add(2);
int position = 0;
if (guesses.Count < 4)
{
for (int y = 0; y < guesses.Count; y++)
{
Console.Out.Write(guesses[y]);
}
}
else
{
for (int i = 1; i <= guesses.Count; i++)
{
if (i%4 == 0)
{
Console.Out.WriteLine(string.Format("{0}{1}{2}{3}", guesses[i - 4], guesses[i - 3],
guesses[i - 2], guesses[i - 1]));
position = i;
}
else
{
if (i == guesses.Count)
{
for (int j = position; j < i; j++)
{
Console.Out.Write(guesses[j]);
}
}
}
}
}

Looping and String Formation

I have a pretty simple general programming problem, yet I can't quite get the results that I am looking for. Basically, I have a DataGridView called dataGridView3 (2 columns), and I want the user to be able to enter as many fields as he/she desires and create a series of strings based on these fields. My problem is that the formed string can only contain 4 elements of the dataGridView at a time, but with my current implementation, it puts every line in first string (see example).
Here is the code that I am currently using.
for (int i = 0; i < dataGridView3.Rows.Count; i++)
{
if (i % 4 == 0)
{
newPA61String += "PA61";
for (int j = i; j < dataGridView3.Rows.Count - 1; j++)
{
newPA61String += " " + (dataGridView3.Rows[j].Cells[0].Value.ToString().PadLeft(5, leftPaddingChar))
+ " " + (dataGridView3.Rows[j].Cells[1].Value.ToString().PadRight(6, rightPaddingChar));
}
newPA61String = newPA61String.PadRight(56, rightPaddingChar);
newPA61String += "\r\n";
}
}
Using 6 rows of data, this code gives me an output of:
PA61 00001 a 00002 b 00003 c 00004 d 00005 e 00006 f
PA61 00005 e 00006 f
I would like it to look like this; however, I can't quite manipulate it the way I want:
PA61 00001 a 00002 b 00003 c 00004 d
PA61 00005 e 00006 f
My first instinct was just to truncate the first string after the specified length was reached, but the string is formed by placing everything on one line split by a "\r\n", so doing that would eliminate anything after the first 4 columns.
I know the solution is probably fairly obvious, but I'm having one of those days...
Thanks in advance, and if you need any additional information, please ask.
Change:
for (int j = i; j < dataGridView3.Rows.Count - 1; j++)
to:
for (int j = i; j < Math.Min(dataGridView3.Rows.Count, i + 4); j++)
And you can move the Math.Min expression out of the loop.
Though I find while loops clearer for this kind of thing.
Iterate over the number of PA61 items to insert, not over the rows and then calculate row and column (or cell) number like this:
for (int i = 0; i < pa61ItemsCount; i++)
{
int row = i / 4;
int cell = i % 4;
...
}

Categories