Show a pyramid based on number input - c#

I'm currently stuck on this problem the goal is to be able to print out a pyramid depending on the input number.
Ex: input = 3
It should look like this:
1
23
I'm able to make it work with some numbers but it doesn't work with other inputs.
The current logic that I follow is by dividing the input by 2 then add the remainder to the next one to be divided.
Example input: 10
10 / 2 = 5 remainder: 0
5 / 2 = 2 remainder: 1
2 + 1 (previous remainder)/ 2 = 1 remainder: 1
1
Whereas it would look like this:
5
2
2
1
The rules of the pyramid that I'm trying to make only needs to have one or two differences per row.
That's why I'll be needing to deduct 1 from 5 and add it to the next one:
4
3
2
1
Thus having pyramid like this: 10
****
***
**
*
The problem is this approach isn't applicable on other inputs and I'm having a hard time on finding a different approach for this.

This code works for your example, although it might be improved to detect whenever a number is not suitable to print a piramid.
static void Main(string[] args)
{
while (true)
{
Console.Write("Enter a number:");
int input = int.Parse(Console.ReadLine());
List<List<string>> piramid = new List<List<string>>();
int rowNumber = 1, dotsCount = 0;
while (dotsCount < input)
{
List<string> row = new List<string>();
for (int i = 1; i <= rowNumber && dotsCount < input; i++)
{
row.Add("*");
dotsCount++;
}
piramid.Add(row);
rowNumber++;
}
Console.WriteLine("Piramid");
Print(piramid);
Console.WriteLine("Piramid (inverted)");
PrintInverted(piramid);
}
}
static void Print(List<List<string>> piramid)
{
foreach (var item in piramid)
{
item.ForEach(Console.Write);
Console.Write("\n");
}
}
static void PrintInverted(List<List<string>> piramid)
{
for (int i = piramid.Count - 1; i >= 0; i--)
{
List<string> item = piramid[i];
item.ForEach(Console.Write);
Console.Write("\n");
}
}

Related

For Loop that counts up and down from a start index inside range

I'm having trouble developing a for-loop that starts at a given integer (start) and then counts up and down from this starting point inside a given range (min to max). I want the result to be in order by distance to the given start. If a for-loop is not the right tool here, i am open for other suggestions!
Since this is hard to explain i have a example down below:
var start = 4;
var max = 10;
var min = 0;
var stepSize = 1;
for(var i=startIndex; i>=min && i<=max; ???) {
Console.WriteLine(i)
}
The result should look like this:
4 5 3 6 2 7 1 8 0 9 10
The really tricky part for me is the end where the alternation has to stop in order to reach the max value of 10 and not go below 0 in the meantime.
I started experimenting and had a solution that would work for the first bit:
const int start = 4;
const int stepSize = 1;
for (var (i,j,k) = (start,1,5); Math.Abs(j)<=11; k=(k+j),j=-j-Math.Sign(j)*stepSize,i=(k+(start-5))%11) {
Console.WriteLine(i);
}
This works fine for the first part where alternation is needed, but it breaks once the alternation needs to stop. The result from this experiment is:
4 5 3 6 2 7 1 8 0 9 -1
Here it is with a for loop, but like others have already alluded to, I think other structures are better suited for your task:
public static void Main() {
int start = 4;
int max = 10;
int min = 0;
int stepSize = 1;
for(int i=start, j=start; i>=min || j<=max; i-=stepSize, j+=stepSize) {
if (i==start) {
Console.Write(i + " ");
}
else {
if (j <= max) {
Console.Write(j + " ");
}
if (i >= min) {
Console.Write(i + " ");
}
}
}
}
The sequence you are after:
4 5 3 6 2 7 1 8 0 9 10
Could be specified as the following:
4 - 3 - 2 - 1 - 0
- 5 - 6 - 7 - 8 - 9 10
- - - - - - - - - - --
4 5 3 6 2 7 1 8 0 9 10
Which using something like MoreLinq, could be expressed like this:
Sequence(4, 0).Interleave(Sequence(5, 10))
Obviously, you control the start, max and min by controlling the values of both sequences. So, say you want to start from 7, going up and down towards 1 as the minimum value, and 14 as the maximum. The call would be like:
Sequence(7, 1).Interleave(Sequence(8, 14))
Lastly, this also allows you to easily change from a "up-down" to a "down-up" by swapping the intervals. Using the example above:
Sequence(8, 14).Interleave(Sequence(7, 1))
Note that Sequence also has an overload that takes a step argument, so you can additionally expand the examples below with arbitrary step increments and not only 1.
Since you explicitly stated that you want a for loop that produces the pattern, how about this approach:
Find the larger "distance" first and let the loop run until this point, not starting with 0. In the loop check in both directions and do the calculations inline and call the method once beforehand with the original value.
int x = 4;
int min = 0;
int max = 10;
int largest = Math.Max(Math.Abs(min - x), Math.Abs(max - x));
YourMethod(x);
for (int i = 1; i <= largest; i++)
{
if (x + i <= max)
YourMethod(x + i);
if (x - i >= min)
YourMethod(x - i);
}
A simple but elegant solution could generate the number sequence you want like so:
static IEnumerable<int>
UpDownCount(int start, int lower, int upper)
{
int i = start, j = start;
yield return start;
while (true)
{
bool ilimit = ++i <= upper,
jlimit = --j >= lower;
if (ilimit)
yield return i;
if (jlimit)
yield return j;
if (!(ilimit || jlimit))
yield break;
}
}
Then you can use that sequence with LINQ or a simple foreach loop:
foreach (int i in UpDownCount(4, 0, 10))
Console.WriteLine(i);

int list won't display in console application

I come from a C++ background creating basic 2D games with it, but I am trying to teach myself C# to a point to where I can get the most basic of jobs using it. I am not in school but I am following the Problems on ProjectEuler.net.
The problem question is commented into the code. I can't tell whether I solved it or not because I can't get the numbers to display from a list into the console application.
I've tried writing to console directly from the variable value with Console.WriteLine but I'm not having any luck. I've also tried converting all int list values to a string value and displaying them but that also didn't work.
I'm not looking for the answer to number 4 just looking to display the list so I can find the answer on my own.
Why can't I get the list to write to the Console?
Any help is appreciated!
static void Main(string[] args)
{
/* A palindromic number reads the same both ways.
* The largest palindrome made from the product of two 2-digit numbers is 9009 = 91 × 99.
Find the largest palindrome made from the product of two 3-digit numbers. */
// 100 x 100 = 10000
// 999 x 999 = 998001
List<int> palindromeContainer = new List<int>();
int Increment = 2;
int Holder = 0;
for (int i = 100; i <= 999; ++i)
{
int j = i;
while (j <= 999)
{
do
{ Holder = i * j; // Gets all Possible Combinations of i * j
if ((Holder % Increment) != 0) // Checks for Prime Numbers
{
++Increment;
}
else if (Increment == Holder - 1 && Holder % Increment != 0 )
{
palindromeContainer.Add(Holder);
Increment = 2;
break;
}
else if (Increment == Holder - 1 && Holder % Increment == 0)
{
Increment = 2;
break;
}
} while (Increment < Holder);
++j;
}
}
palindromeContainer.Sort();
foreach (int line in palindromeContainer)
{
Console.WriteLine(line); // Display all items in list
}
Firstly comment out your loop logic and test without:
List<int> palindromeContainer = new List<int>();
palindromeContainer.Add(2);
palindromeContainer.Add(1);
palindromeContainer.Sort();
foreach (int line in palindromeContainer)
{
Console.WriteLine(line); // Display all items in list
}
Console.ReadLine();
This will output to the console. Then you will know this is working and console output is not the problem.

c# Hackerrank code terminated due to time out but there is no way to optimize this code further?

I was doing a hacker rank challenge in c# to try and bring some of my c skills over to c#. Now I know hacker rank is notoriously stupid with killing programs due to time out (in this case if it lasts more than 3 seconds). But I honestly cannot think of a way to optimize this code further.
Here are the instructions:
https://www.hackerrank.com/challenges/ctci-array-left-rotation
Basically the challenge is to shift an array of numbers some x amount of times over in the left direction inside the array.
To my knowledge this code is as minimal as it can get and still do the thing they requested. The only way I can think to optimize this code further is to merge the constraint "if(a[i] > 1000000 || a[i] < 1 )" with the writeline forloop at the end of the code, but I tried that and it didn't work.
To me this is literally the minimum number of operations to move the array over by an amount x. But the code fails in test case 7 and 8 (out of 8) due to time out. Am I missing something?
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
class Solution
{
static void Main(String[] args)
{
int i, j;
int temp = 0;
string[] tokens_n = Console.ReadLine().Split(' ');
int n = Convert.ToInt32(tokens_n[0]);
int k = Convert.ToInt32(tokens_n[1]);
string[] a_temp = Console.ReadLine().Split(' ');
int[] a = Array.ConvertAll(a_temp,Int32.Parse);
//constraints
if(n >= 100000 || n < 1 )
{
System.Environment.Exit(1);
}
if(k > n || n < 1 )
{
System.Environment.Exit(1);
}
for(i = 0; i< n; i++)
{
if(a[i] > 1000000 || a[i] < 1 )
{
System.Environment.Exit(1);
}
}
//double for loop. one adjust position by one. then repeat k number of times.
for(j = 0; j<k; j++)
{
for(i = 0; i< n-1; i++)
{
temp = a[i];
a[i] = a[i+1];
a[i+1] = temp;
}
}
//view array
for(i = 0; i< n; i++)
{
Console.Write(a[i] + " " );
}
}
}
I used a queue mechanism to get this working. That way you don't have to do any array copy and just rotating the string to the end.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
class Solution {
static int[] leftRotation(int[] arr, int rotation) {
Queue<int> queue = new Queue<int>(arr);
for (int i = 0; i < rotation; i++)
{
queue.Enqueue(queue.Dequeue());
}
return queue.ToArray();
}
static void Main(String[] args) {
string[] tokens_n = Console.ReadLine().Split(' ');
int n = Convert.ToInt32(tokens_n[0]);
int d = Convert.ToInt32(tokens_n[1]);
string[] a_temp = Console.ReadLine().Split(' ');
int[] a = Array.ConvertAll(a_temp,Int32.Parse);
int[] result = leftRotation(a, d);
Console.WriteLine(String.Join(" ", result));
}
}
Shuffling the values one at a time is very slow. There is no need to do this. One can think of the rotation as moving 2 blocks - the values to the left of the rotation point and the values including and to the right of the rotation point
1 2 3 4 5 6 7 8 9
Rotate this 3 times is
move 1-3 to a temp variable
move 4-9 to the start of the array
move 1-3 to the end of 4-9
Edit: Add a bit more detail
We want to rotate the array 3 places.
move 1 2 3 to a temporary array
1 2 3
1 2 3 4 5 6 7 8 9
move 4-9 to the start of the array
1 2 3
4 5 6 7 8 9 7 8 9
move 1-3 to the end of the array
1 2 3
4 5 6 7 8 9 1 2 3
We can get away without the temp array for the left hand block if we create a new target array and copy everything to it. The following passes all the tests for the problem
var result = new int[a.Length];
var block2Length = a.Length - k;
Array.Copy(a, k, result, 0, block2Length);
Array.Copy(a, 0, result, block2Length, k);
Console.WriteLine(string.Join(" ", result.Select(v => v.ToString())));
Other Points
The constraints in HackerRank are part of the problem definition - they are telling us what the values can/will do so that we don't have to worry about solving a more general problem
e.g.
1 <= a[i] < 10^6
tells us the numbers will all be within the range for standard integers, no need to use long or BigInteger. As part of the solution we don't need to confirm these. In a real world situation different rules apply but here we have as much code checking values that cannot be wrong as we have solving the problem.
This has already been answered but there is a different solution that is very fast:
The idea is that you use the periodicity of the shifting. Shifting an element n+1 times is the same as shifting it 1 time which boils down to k % n.
Thus, you can simply create a new array and move the "old" elements directly to the correct spot. See the sample code below:
static void Main(String[] args) {
string[] tokens_n = Console.ReadLine().Split(' ');
int n = Convert.ToInt32(tokens_n[0]);
int k = Convert.ToInt32(tokens_n[1]);
string[] a_temp = Console.ReadLine().Split(' ');
int[] a = Array.ConvertAll(a_temp,Int32.Parse);
// use the periodicity of the shifting creating a shift between 0 and n - 1.
int shifts = k % n;
// Create a new array to hold the elements at their new positions.
int[] newPositions = new int[a.Length];
// You only need to iterate of the array once assigning each element its new position.
for(int i= 0; i < a.Length; ++i)
{
// Here is the magic: (for clarification see table below)
int position = (i - shifts + n)%n;
newPositions[position] = a[i];
}
foreach(var element in newPositions)
Console.Write($"{element} ");
}
This is more intuitive once you write it down on paper. The table might prints more values than the array contains to show the actual positions in the array.
-4 -3 -2 -1 | 0 1 2 3 4 (array indices)
=============================
2 3 4 5 | 1 2 3 4 5 (array contents without shift)
3 4 5 1 | 2 3 4 5 1 (shifted 1 time)
4 5 1 2 | 3 4 5 1 2 (shifted 2 times)
5 1 2 3 | 4 5 1 2 3 (shifted 3 times)
1 2 3 4 | 5 1 2 3 4 (shifted 4 times)
formula: i - k + n
results:
i=0: 0 - 4 + 5 = 1
i=1: 1 - 4 + 5 = 2
i=2: 2 - 4 + 5 = 3
i=3: 3 - 4 + 5 = 4
i=4: 4 - 4 + 5 = 5
i=5: 5 - 4 + 5 = 6 => 0
EDIT: I skipped the parts to check the boundaries for the sake of simplicity.
Updated answer.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
class Solution
{
static void Main(String[] args)
{
int i, j, z;
string[] tokens_n = Console.ReadLine().Split(' ');
int n = Convert.ToInt32(tokens_n[0]);
int k = Convert.ToInt32(tokens_n[1]);
string[] a_temp = Console.ReadLine().Split(' ');
int[] a = Array.ConvertAll(a_temp,Int32.Parse);
int[] temparray = new int[2*n];
//constraints
if(n >= 100000 || n < 1 )
{
System.Environment.Exit(1);
}
if(k > n || n < 1 )
{
System.Environment.Exit(1);
}
for(i = 0; i< n; i++)
{
if(a[i] > 1000000 || a[i] < 1 )
{
System.Environment.Exit(1);
}
}
for(j = 0; j<n; j++)
{
z = (j-k) %n;
if(z != 0)
{
z= (n+ z) %n;
}
temparray[z] = a[j];
}
//view array
for(i = 0; i< n; i++)
{
Console.Write(temparray[i] + " " );
}
}
}

Increase chances of name being picked from Array

For my program, I've prompted the user to put 20 names into an array (the array size is 5 for testing for now), this array is then sent to a text document. I need to make it so that it will randomly pick a name from the list and display it (which I have done). But I now need to make it increase the chances of a name being picked, how would I go about doing this?
Eg. I want to increase the chances of the name 'Jim' being picked from the array.
class Programt
{
static void readFile()
{
}
static void Main(string[] args)
{
string winner;
string file = #"C:\names.txt";
string[] classNames = new string[5];
Random RandString = new Random();
Console.ForegroundColor = ConsoleColor.White;
if (File.Exists(file))
{
Console.WriteLine("Names in the text document are: ");
foreach (var displayFile in File.ReadAllLines(file))
Console.WriteLine(displayFile);
Console.ReadKey();
}
else
{
Console.WriteLine("Please enter 5 names:");
for (int i = 0; i < 5; i++)
classNames[i] = Console.ReadLine();
File.Create(file).Close();
File.WriteAllLines(file, classNames);
Console.WriteLine("Writing names to file...");
winner = classNames[RandString.Next(0, classNames.Length)];
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("\nThe winner of the randomiser is: {0} Congratulations! ", winner);
Thread.Sleep(3000);
Console.Write("Completed");
Thread.Sleep(1000);
}
}
}
There's two ways of doing this. You can either produce a RNG with a normal distribution targeting one number.
Or the simpler way is a translational step. Generate in the range 0-100 and then produce code which translates to the answer in a biased way e.g.
0-5 : Answer 1
6-10: Answer 2
11-90: Answer 3
91-95: Answer 4
96-100: Answer 5
This gives an 80% chance of picking Answer 3, the others only get a 5% chance
So where you currently have RandString.Next(0, classNames.Length) you can replace that with a function something like GetBiasedIndex(0, classNames.Length, 3)
The function would look something like this (with test code):
public Form1()
{
InitializeComponent();
int[] results = new int[5];
Random RandString = new Random();
for (int i = 0; i < 1000; i++)
{
var output = GetBiasedIndex(RandString, 0, 4, 3);
results[output]++;
}
StringBuilder builder = new StringBuilder();
for (int i = 0; i < 5; i++)
{
builder.AppendLine(results[i].ToString());
}
label1.Text = builder.ToString();
}
private int GetBiasedIndex(Random rng, int start, int end, int target)
{
//Number between 0 and 100 (Helps to think percentage)
var check = rng.Next(0, 100);
//There's a few ways to do this next bit, but I'll try to keep it simple
//Allocate x% to the target and split the remaining y% among all the others
int x = 80;//80% chance of target
int remaining = 100 - x;//20% chance of something else
//Take the check for the target out of the last x% (we can take it out of any x% chunk but this makes it simpler
if (check > (100 - x))
{
return target;
}
else
{
//20% left if there's 4 names remaining that's 5% each
var perOther = (100 - x) / ((end - start) - 1);
//result is now in the range 0..4
var result = check / perOther;
//avoid hitting the target in this section
if (result >= target)
{
//adjust the index we are returning since we have already accounted for the target
result++;
}
//return the index;
return result;
}
}
and the output:
52
68
55
786
39
If you're going to call this function repeatedly you'll need to pass in the instance of the RNG so that you don't reset the seed each call.
If you want to target a name instead of an index you just need to look up that name first and have an else condition for when that name isn't found

How to check how many times a value appears in an array?

So this is what I want my output to look like:
How many numbers? 10
Give number 1: 1
Give number 2: 3
Give number 3: 1
Give number 4: 3
Give number 5: 4
Give number 6: 6
Give number 7: 4
Give number 8: 8
Give number 9: 2
Give number 10: 1
Number 1 appeared 3 times
Number 2 appeared 1 times
Number 3 appeared 2 times
Number 4 appeared 2 times
Number 6 appeared 1 times
Number 8 appeared 1 times
The thing is, I've got the part which reads the user input done. However, I have no idea how to continue with the part which tells how many times each number appeared.
Also, I'm doing this as a schoolwork so most of the code is in Finnish. I hope you can still understand it, though.
using System;
namespace Ohjelma
{
class Ohjelma
{
static void Main()
{
Console.Write("Kuinka monta lukua? ");
int pituus = Convert.ToInt32(Console.ReadLine());
int[] luvut = new int[pituus];
for (int i = 0; i < pituus; i++)
{
Console.Write("Anna {0}. luku:", i + 1);
luvut[i] = Convert.ToInt32(Console.ReadLine());
}
for (int i = 0; i < luvut.Length; i++)
{
Console.Write(luvut[i]);
}
Console.ReadLine();
}
}
}
Edit: Sorry about the code block on the example of what it should output, not exactly sure how to use blockquotes even though I tried. Thanks!
You can use LINQ like:
var query = luvut.GroupBy(r => r)
.Select(grp => new
{
Value = grp.Key,
Count = grp.Count()
});
For output you can use:
foreach (var item in query)
{
Console.WriteLine("Value: {0}, Count: {1}", item.Value, item.Count);
}
int[] num = { 1, 1, 1, 3, 3, 4, 5, 6, 7, 0 };
int[] count = new int[10];
//Loop through 0-9 and count the occurances
for (int x = 0; x < 10; x++){
for (int y = 0; y < num.Length; y++){
if (num[y] == x)
count[x]++;
}
}
//For displaying output only
for (int x = 0; x < 10; x++)
Console.WriteLine("Number " + x + " appears " + count[x] + " times");
Program Output:
Number 0 appears 1 times
Number 1 appears 3 times
Number 2 appears 0 times
Number 3 appears 2 times
Number 4 appears 1 times
Number 5 appears 1 times
Number 6 appears 1 times
Number 7 appears 1 times
Number 8 appears 0 times
I understand how bad it feels when all your classmates had finish theirs, and you are still struggling. My codes should be simple enough for your learning.
If you don't want to use LINQ, you can code as follows:-
public class Program
{
public static void Main()
{
int[] arr1 = new int[] {1,3,3,5,5,4,1,2,3,4,5,5,5};
List<int> listArr1 = arr1.ToList();
Dictionary<int,int> dict1 = new Dictionary<int,int>();
foreach(int i in listArr1)
{
if(dict1.ContainsKey(i))
{
int value = dict1[i];
value++;
dict1[i]= value;
}
else
{
dict1.Add(i,1);
}
}
for(int x = 0 ; x < dict1.Count(); x++)
{
Console.WriteLine("Value {0} is repeated {1} times", dict1.Keys.ElementAt(x),dict1[dict1.Keys.ElementAt(x)]);
}
}
}

Categories