Whats the appropriate condition to end my for loop? - c#

I need to add the following intervals to the for loop (I tried with if statements and the teacher asked me to reduce the amount of coding).
Intervals (Pizza Diameters)
12 - 20 = 8 slices
21 - 24 = 12 slices
25 - 30 = 16 slices
31 - 36 = 24 slices
The following code gives me output that's pretty close to what I need, except that it doesn't adhere to the conditions above. For example if I enter 24 it should only give me the output for 8 and 12 slices.
int[] pizzaSlices = new int[4] { 8, 12, 16, 24 };
for (int i = pizzaSlices[0]; i < inputDiameter; i++) {
if (i == pizzaSlices[0] || i == pizzaSlices[1] || i == pizzaSlices[2] ||
i == pizzaSlices[3]) {
Console.WriteLine("cut in " + i + " slices results in a slice area of " +
Math.Round(areaOfThePizza / i, 2) + " per slices");
}
}
Current Output:
Desired Output:

I couldn't resist adding a somewhat LINQ'y solution:
[Test]
[TestCase(37, Result = 0)]
[TestCase(36, Result = 24)]
[TestCase(35, Result = 24)]
[TestCase(30, Result = 16)]
[TestCase(29, Result = 16)]
[TestCase(26, Result = 16)]
[TestCase(22, Result = 12)]
[TestCase(12, Result = 8)]
[TestCase(11, Result = 0)]
[TestCase(10, Result = 0)]
public int GetNumberOfSlices(int diameter)
{
var pizzas = new[] {
new[] { 11, 0 },
new[] { 20, 8 },
new[] { 24, 12 },
new[] { 30, 16 },
new[] { 36, 24 }
};
var pizza = pizzas.FirstOrDefault(p => diameter <= p[0]);
return pizza == null ? 0 : pizza[1];
}

I added another int array to hold the pizza diameters. The for loop iterates from 0 to the length of pizzaSlices, so 0 to 3.
The if statement in the for loop checks if the user entered diameter is in the range of the current iteration's pizzaDims counterpart.
int[] pizzaSlices = new int[4] { 8, 12, 16, 24 };
int[] pizzaDims = new int[4] { 12, 21, 25, 31 }; // pizza diameters array
if(inputDiameter >= smallest) {
for (int i = 0; i <= pizzaSlices.Length; i++) {
if(inputDiameter >= pizzaDims[i] {
Console.WriteLine("cut in " + pizzaSlices[i] +
" slices results in a slice area of " +
Math.Round(areaOfThePizza / pizzaSlices[i], 2) +
" per slices");
} else {
break; // no need to continue iterating, if one condition is false then
// the rest will be as well
}
}
}

Related

How to dynamically add indexes values of an array in C#?

I have an array where the first two smallest values have to be added, and consequently the result has to be added to next smallest and so on until it reaches the end of the array to give a final total.
However, how can I dynamically modify the method/function so if the values changes and I have 6 vehicles and 6 specs values in the array, the return of the method/function total is not restricted to just 4 indexes.
The array values are unsorted, so in order to add the first smallest, it has to be sorted. Once that's done it adds the values of the new array.
Here's what I've tried:
public static int vehicles = 4;
public static int[] specs = new int[] { 40, 8, 16, 6 };
public static int time(int vehicles, int[] specs)
{
int newValue = 0;
for (int i = 1; i < vehicles; i++)
{
newValue = specs[i];
int j = i;
while (j > 0 && specs[j - 1] > newValue)
{
specs[j] = specs[j - 1];
j--;
}
specs[j] = newValue;
}
// How can I dynamically change this below:
int result1 = specs[0] + specs[1];
int result2 = result1 + specs[2];
int result3 = result2 + specs[3];
int total = result1 + result2 + result3;
return total; // Returns 114
}
Here's the idea of how it works:
4, [40, 8, 16, 6] = 14 --> [40, 14, 16] = 30 --> [40, 30] = 70 ==>> 14 + 30 + 70 = 114
6, [62, 14, 2, 6, 28, 41 ] = 8 --> [62, 14, 8, 28, 41 ] --> 22 [62, 22, 28, 41 ] --> 50
[62, 50, 41 ] --> 91 [62, 91 ] --> 153 ==> 8 + 22 + 50 + 91 + 153 = 324
First off, if you are not restricted to arrays for some weird reason use List<int> and your life will be easier.
List<int> integers = { 14, 6, 12, 8 };
integers.Sort();
integers.Reverse();
while( integers.Count > 1 )
{
int i = integers[integers.Count - 1];
int j = integers[integers.Count - 2];
integers[integers.Count - 2] = i + j;
integers.RemoveAt(integers.Count - 1);
}
var result = integers[0];
P.S.: This can be easily modified to operate on the array version, you can't RemoveAt() from an array but can separately maintain a lastValidIndex.
I would go with the simplest version of a one line solution using LINQ:
Array.Sort(specs);
int total = specs.Select((n, i) => specs.Take(i + 1).Sum()).Sum() - (specs.Length > 1 ? specs[0] : 0);
I would use Linq.
Enumerable.Range(2, specs.Length - 1)
.Select(i => specs
.Take(i)
.Sum())
.Sum();
Explanation:
We take a range starting from 2 ending with specs.Length.
We sum the first i values of specs where i is the current value in the range.
After we have all those sums, we sum them up as well.
To learn more about linq, start here.
This code only works if the values have been sorted already.
If you want to sort the values using linq, you should use this:
IEnumerable<int> sorted = specs.OrderBy(x => x);
Enumerable.Range(2, sorted.Count() - 1)
.Select(i => sorted
.Take(i)
.Sum())
.Sum();
The OrderBy function needs to know how to get the value it should use to compare the array values. Because the array values are the values we want to compare we can just select them using x => x. This lamba takes the value and returns it again.
See comments in code for explanation.
using System;
using System.Linq;
class Program
{
static void Main()
{
//var inputs = new [] { 40, 8, 16, 6 }; // total = 114
var inputs = new[] { 62, 14, 2, 6, 28, 41 }; // total = 324
var total = 0;
var query = inputs.AsEnumerable();
while (query.Count() > 1)
{
// sort the numbers
var sorted = query.OrderBy(x => x).ToList();
// get sum of the first two smallest numbers
var sumTwoSmallest = sorted.Take(2).Sum();
// count total
total += sumTwoSmallest;
// remove the first two smallest numbers
query = sorted.Skip(2);
// add the sum of the two smallest numbers into the numbers
query = query.Append(sumTwoSmallest);
}
Console.WriteLine($"Total = {total}");
Console.WriteLine("Press any key...");
Console.ReadKey(true);
}
}
I benchmark my code and the result was bad when dealing with large dataset. I suspect it was because of the sorting in the loop. The sorting is needed because I need to find the 2 smallest numbers in each iteration. So I think I need a better way to solve this. I use a PriorityQueue (from visualstudiomagazine.com) because the elements are dequeued based on priority, smaller numbers have higher priority in this case.
long total = 0;
while (pq.Count() > 0)
{
// get two smallest numbers when the priority queue is not empty
int sum = (pq.Count() > 0 ? pq.Dequeue() : 0) + (pq.Count() > 0 ? pq.Dequeue() : 0);
total += sum;
// put the sum of two smallest numbers in the priority queue if the queue is not empty
if (pq.Count() > 0) pq.Enqueue(sum);
}
Here's some benchmark results of the new (priority queue) code and the old code in release build. Results are in milliseconds. I didn't test the 1 million data with the old code because it's too slow.
+---------+----------+-------------+
| Data | New | Old |
+---------+----------+-------------+
| 10000 | 3.9158 | 5125.9231 |
| 50000 | 16.8375 | 147219.4267 |
| 1000000 | 406.8693 | |
+---------+----------+-------------+
Full code:
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
class Program
{
static void Main()
{
const string fileName = #"numbers.txt";
using (var writer = new StreamWriter(fileName))
{
var random = new Random();
for (var i = 0; i < 10000; i++)
writer.WriteLine(random.Next(100));
writer.Close();
}
var sw = new Stopwatch();
var pq = new PriorityQueue<int>();
var numbers = File.ReadAllLines(fileName);
foreach (var number in numbers)
pq.Enqueue(Convert.ToInt32(number));
long total = 0;
sw.Start();
while (pq.Count() > 0)
{
// get two smallest numbers when the priority queue is not empty
int sum = (pq.Count() > 0 ? pq.Dequeue() : 0) + (pq.Count() > 0 ? pq.Dequeue() : 0);
total += sum;
// put the sum of two smallest numbers in the priority queue if the queue is not empty
if (pq.Count() > 0) pq.Enqueue(sum);
}
sw.Stop();
Console.WriteLine($"Total = {total}");
Console.WriteLine($"Time = {sw.Elapsed.TotalMilliseconds}");
total = 0;
var query = File.ReadAllLines(fileName).Select(x => Convert.ToInt32(x));
sw.Restart();
while (query.Count() > 0)
{
// sort the numbers
var sorted = query.OrderBy(x => x).ToList();
// get sum of the first two smallest numbers
var sumTwoSmallest = sorted.Take(2).Sum();
// count total
total += sumTwoSmallest;
// remove the first two smallest numbers
query = sorted.Skip(2);
// add the sum of the two smallest numbers into the numbers
if (query.Count() > 0)
query = query.Append(sumTwoSmallest);
}
sw.Stop();
Console.WriteLine($"Total = {total}");
Console.WriteLine($"Time = {sw.Elapsed.TotalMilliseconds}");
Console.WriteLine("Press any key...");
Console.ReadKey(true);
}
}
PriorityQueue code:
using System;
using System.Collections.Generic;
// From http://visualstudiomagazine.com/articles/2012/11/01/priority-queues-with-c.aspx
public class PriorityQueue<T> where T : IComparable<T>
{
private List<T> data;
public PriorityQueue()
{
this.data = new List<T>();
}
public void Enqueue(T item)
{
data.Add(item);
int ci = data.Count - 1; // child index; start at end
while (ci > 0)
{
int pi = (ci - 1) / 2; // parent index
if (data[ci].CompareTo(data[pi]) >= 0)
break; // child item is larger than (or equal) parent so we're done
T tmp = data[ci];
data[ci] = data[pi];
data[pi] = tmp;
ci = pi;
}
}
public T Dequeue()
{
// assumes pq is not empty; up to calling code
int li = data.Count - 1; // last index (before removal)
T frontItem = data[0]; // fetch the front
data[0] = data[li];
data.RemoveAt(li);
--li; // last index (after removal)
int pi = 0; // parent index. start at front of pq
while (true)
{
int ci = pi * 2 + 1; // left child index of parent
if (ci > li)
break; // no children so done
int rc = ci + 1; // right child
if (rc <= li && data[rc].CompareTo(data[ci]) < 0) // if there is a rc (ci + 1), and it is smaller than left child, use the rc instead
ci = rc;
if (data[pi].CompareTo(data[ci]) <= 0)
break; // parent is smaller than (or equal to) smallest child so done
T tmp = data[pi];
data[pi] = data[ci];
data[ci] = tmp; // swap parent and child
pi = ci;
}
return frontItem;
}
public T Peek()
{
T frontItem = data[0];
return frontItem;
}
public int Count()
{
return data.Count;
}
public override string ToString()
{
string s = "";
for (int i = 0; i < data.Count; ++i)
s += data[i].ToString() + " ";
s += "count = " + data.Count;
return s;
}
public bool IsConsistent()
{
// is the heap property true for all data?
if (data.Count == 0)
return true;
int li = data.Count - 1; // last index
for (int pi = 0; pi < data.Count; ++pi)
{ // each parent index
int lci = 2 * pi + 1; // left child index
int rci = 2 * pi + 2; // right child index
if (lci <= li && data[pi].CompareTo(data[lci]) > 0)
return false; // if lc exists and it's greater than parent then bad.
if (rci <= li && data[pi].CompareTo(data[rci]) > 0)
return false; // check the right child too.
}
return true; // passed all checks
}
// IsConsistent
}
// PriorityQueue
Reference:
https://visualstudiomagazine.com/articles/2012/11/01/priority-queues-with-c.aspx
https://en.wikipedia.org/wiki/Priority_queue
You can simply sort it using Array.Sort(), then get the sums in a new array which starts with the smallest value and add each next value to the most recent sum, the total will be the value of the last sum.
public static int time(int vehicles, int[] specs)
{
int i, total;
int[] sums = new int[vehicles];
Array.Sort(spec);
sums[0] = specs[0];
for (i = 1; i < vehicles; i++)
sums[i] = sums[i - 1] + spec[i];
total = sums[spec - 1];
}

Get range in multiplication of 5

I have a number. For instance, my number is 19 . Then I want to populate my drop down with range in multiplication of 5. So my dropdownlist will consist of items of:
1-5
6-10
11-15
16-19
I tried modulus and division, however, I can't seems to get the range. Is there a fixed method?
Sample code
List<string> range = new List<string>();
int number = 19;
int numOfOccur = (19/5);
for (int i = 1; i < numOfOccur ; i++)
{
range.Add(i + " - " + (i * 5))
}
Sometime I think that old school code, without fancy linq is a bit more clear
int maximum = 19;
int multiple = 5;
int init = 1;
while (init + multiple <= maximum )
{
string addToDDL = init.ToString() + "-" + (init + multiple - 1).ToString();
Console.WriteLine(addToDDL);
init += multiple;
}
if(init <= maximum)
{
string last = init.ToString() + "-" + maximum.ToString();
Console.WriteLine(last);
}
Linq solution (modern techs allow us to put it consize):
int number = 19;
int div = 5;
List<string> range = Enumerable
.Range(0, number / div + (number % div == 0 ? 0 : 1))
.Select(i => $"{i * div + 1} - {Math.Min((i + 1) * div, number)}")
.ToList();
Test
Console.Write(string.Join(Environment.NewLine, range));
Returns
1 - 5
6 - 10
11 - 15
16 - 19
When using modulo arithmetics, do not forget about remainders: you have an error in int numOfOccur = (19/5); line. It should be
int numOfOccur = 19 / 5 + (19 % 5 == 0 ? 0 : 1);
for the last incomplete 16 - 19 range to be proceeded.
Add this package to your project : https://www.nuget.org/packages/System.Interactive/
Then you can do this:
IEnumerable<IList<int>> buffers2 = Enumerable.Range(1, 19).Buffer(5);
IList<int>[] result2 = buffers2.ToArray();
// { { 1, 2, 3, 4, 5 }, { 6, 7, 8, 9, 10 }, ...
Don't forget to add System.Interactive namespace to your using block.

Replace byte 10 by 10 10

Hi I want to replace a byte[] where ever there is 10 by 10 10. here is my code.
if i have my data as "10 20 10 20 40 50 50 50 50 10 03" i want to replce it by
"10 20 10 10 20 40 50 50 50 50 10 10 03"
note: first byte is untouched
plse follow my comment, my idea is to push the byte array to nxt position and add another 10.
foreach (var b in command.ToBytes())
{
// var c = b;
transmitBuffer[count++] = b; data is formed here
addedbuffer[addall++] = b; duplication is made
}
if (addedbuffer[0] == 16 && addedbuffer[1] == 32 || addedbuffer[50] == 16 && addedbuffer[51] == 03) /
{
/condition on which to enter here
addedbuffer[0] = 0; //making 1st and 2nd value as null
addedbuffer[1] = 0;
for (int i = 0; i < addedbuffer.Length; i++) //till length i will chk
{
if (addedbuffer[i] == 10) //replace 10 by 10 10
addedbuffer[i] = 1010; // error,
}
}
You can't insert into array (you can do it with List<T>), so it looks that you have to create a new array; Linq solution:
Byte[] source = new Byte[] {
20, 10, 20, 40, 50, 50, 50, 50, 10, 03
};
var result = source
.SelectMany((item, index) =>
item == 10 && index != 0 ? new Byte[] { item, item } : new Byte[] { item })
.ToArray();
However, using List<Byte> (in order just to insert 10's) instead of Byte[] is a better way out:
List<Byte> list = List<Byte>() {
20, 10, 20, 40, 50, 50, 50, 50, 10, 03
};
// In order not to read inserted 10's we loop backward
// i >= 1: 1st byte should be preserved as is even if its == 10
for (int i = list.Count - 1; i >= 1; --i)
if (list[i] == 10)
list.Insert(i + 1, 10);
It helps to think of sequences like arrays (IEnumerable<T> in C#) as things that can be transformed into new sequences. Much like numbers can be transformed when you send them into a function, sequences can be, too.
Consider if I have a function that is defined as Add10If10(Byte b). It might looks like this:
public static Byte Add10If10(Byte b)
{
if (b == 10)
{
return b + 10;
}
return b;
}
Numbers which go into this are transformed based on the condition, and come out either 10 larger or the same. The same can be done with sequences, you can take a sequence with some number of elements, and transform it so it has more elements. The result is a new sequence:
public static IEnumerable<Byte> AddAdditional10If10(IEnumerable<Byte> values)
{
foreach (var b in values)
{
if (b == 10)
{
yield return 10;
}
yield return b;
}
}
This function returns an additional 10 for every 10 it encounters. Now that you have the right sequence, you can change how it is stored by changing it to an array:
AddAdditional10If10(addedbuffer).ToArray();
This works via conversion to strings, using String.Replace and converting back:
byte[] source = new Byte[] { 20, 10, 20, 40, 50, 50, 50, 50, 10, 03 };
string[] strArr = Array.ConvertAll(source, b => b.ToString());
string[] replArr = String.Join(" ", strArr).Replace("10", "10 10").Split();
byte[] newArr = Array.ConvertAll(replArr, str => Byte.Parse(str));
Edit:
Another approach with LINQ - elements at first and last indexes and all elements not equal to 10 are unchanged, for all remaining 10s it returns a sequence of 2 10s:
byte[] res = source.SelectMany((b, index) => index == 0
|| index == source.Length - 1
|| b != 10 ?
Enumerable.Repeat(b, 1) : Enumerable.Repeat(b, 2))
.ToArray();
This is a fairly efficient way to do it (requires two passes over the input array, but does not require any resizing of the output array):
public static byte[] Replace10With1010ExcludingFirstByte(byte[] input)
{
// Count 10s excluding first byte.
int count = input.Skip(1).Count(b => b == 10);
// Create output array of appropriate size.
byte[] result = new byte[input.Length + count];
// Copy input to output, duplicating all 10s that are not the first byte.
result[0] = input[0];
for (int i = 1, j = 1; i < input.Length; ++i, ++j)
{
result[j] = input[i];
if (input[i] == 10)
result[++j] = 10;
}
return result;
}
Call it with your original array, and use the returned array instead.
Test code (for use in a Console app):
byte[] input = {10, 20, 10, 20, 40, 50, 50, 50, 50, 10, 03};
var result = Replace10With1010ExcludingFirstByte(input);
Console.WriteLine(string.Join(", ", result));
[EDIT] It seems from one of your comments to another answer that you also want to also exclude the last byte from conversion too.
If so, use this code instead:
public static byte[] Replace10With1010ExcludingFirstAndLastByte(byte[] input)
{
// Count 10s excluding first and last byte.
int count = input.Skip(1).Take(input.Length-2).Count(b => b == 10);
// Create output array of appropriate size.
byte[] result = new byte[input.Length + count];
// Copy input to output, duplicating all 10s that are not the first byte.
result[0] = input[0];
for (int i = 1, j = 1; i < input.Length; ++i, ++j)
{
result[j] = input[i];
if ((input[i] == 10) && (i != (input.Length-1)))
result[++j] = 10;
}
return result;
}

Acces a Row in a 2 dimensional array

I have a multidimentional array like this one with about 3000 rows and 200 columns:
+--+--+--+
|21|23|41|
+--+--+--+
|11|14|16| // 11 is the smalles value in 2nd row
+--+--+--+
|43|35|23|
+--+--+--+
I want to determine the smalles value of the second row.
Is there a better / more readable / linq solution? I currently use a for-loop?
My current Approach:
int min = array[0,1];
for (int i= 1; i<len;i++)
{
if (array[i,1] < min)
{
min = array[i,1];
}
}
Let arr be the array and l.u == 1 suggests second row:
arr.Select((t, u) => new { u, t }).Where(l => l.u == 1).FirstOrDefault().t.Min();
found a working solution
int[,] array = new int[3, 3] { { 21, 23, 41 }, { 11, 14, 16 }, { 43, 35, 23 } };
int min = Enumerable.Range(0, array.GetLength(1)).Min(i => array[1, i]);
Console.WriteLine(min); // 11

Finding sequential Numbers

I have a set of numbers List<int> (for example) : 1, 3, 4, 5, 7, 12, 13, 14, 15, 20, 22, 24, 28, 29, 30
I want to have them grouped as sequential like :
Sequence1 = from 1 amount 1 (1)
Sequence2 = from 3 amount 3 (3, 4, 5)
Sequence3 = from 7 amount 1 (7)
Sequence4 = from 12 amount 4 (12, 13, 14, 15)
Sequence5 = from 20 amount 1 (20)
Sequence6 = from 22 amount 1 (22)
Sequence7 = from 24 amount 1 (24)
Sequence8 = from 28 amount 3 (28, 29, 30)
I know how to do it with a for and checking for each number. Is there an more elegant way or an algorithm, or some sql/lambda command that would help me ?
If the input is sorted, and you really want to avoid a foreach loop, you can use:
list.Select((value,index)=>new {value,index}).GroupBy(x=>x.value-x.index,x=>x.value).Select(g=>g.AsEnumerable())
One could also write a general helper method:
public static IEnumerable<IEnumerable<T>> SplitBetween<T>(this IEnumerable<T> sequence, Func<T,T,bool> predicate)
{
T previous=default(T);
List<T> list=new List<T>();
int index=0;
foreach(T current in sequence)
{
if((index>0)&&predicate(previous,current))
{
yield return list.ToArray();
list.Clear();
}
list.Add(current);
previous=current;
index++;
}
if(list.Count>0)
yield return list.ToArray();
}
And then use it with list.SplitBetween((previous,current) => previous+1 != current)
I don't think that this is very "elegant", but here is my suggestion, hopefully it helps you:
var list = new List<int> { 1, 3, 4, 5, 7, 12, 13, 14, 15, 20, 22, 24, 28, 29, 30 };
int offset = 0;
int sequence = 0;
do
{
int offset1 = offset;
var subList = list.Skip(offset).TakeWhile((item, index) => (index == 0) || (item == (list[offset1 + index - 1] + 1))).ToList();
offset += subList.Count();
sequence++;
Debug.WriteLine("Sequence {0} from {1} amount {2} ({3})", sequence, subList[0], subList.Count(), string.Join(" ", subList));
}
while (offset < list.Count);
int n = 12;//your number
int x = list.IndexOf(n);
var result = list.Skip(x).TakeWhile((value, index) => value - index == n);

Categories