You can only display 60 characters per line - c#

When running this program, my first line has 62 digits while the other lines only have 60. How can I place 2 spaces in front of the first line so each line of the array is no more then 60 characters? So basically it would look like ( with two spaces in the beginning)
9999999999999999999999999999999999999999999999999999999999
999999999999999999999999999999999999999999999999999999999999
999999999999999999999999999999999999999999999999999999999999
using System;
namespace BigFactorial
{
class Program
{
static int MAX = 5000;
//This is telling the program what to multiply.
private static void mult(int[] x, int n)
{
int y = 0, i, m;
for (i = 0; i < MAX; i++)
{
m = y + x[i] * n;
x[i] = m % 10000;
y = m / 10000;
}
}
//This is telling the program how to calculate factorial of n.
public static void Factorial(int[] a, int n)
{
a[0] = 1;
for (int i = n; i > 1; i--)
{
mult(a, i);
}
}
//This is displaing the factorial after the calculation.
public static void Display(int[] a)
{
int i;
for (i = MAX - 1; a[i] == 0; i--) ;
Console.Write(a[i]);
for (int j = i - 1, c = 1; j >= 0; j--, c++)
{
string s = "" + a[j];
Console.Write(s.PadLeft(4, '0'));
if (c % 15 == 0)
Console.WriteLine();
}
Console.WriteLine();
}
public static void Main(string[] args)
{
while (true)
{
//Telling user to enter a number.
Console.Write("Enter a number to factor or a negative number to quit: ");
int n = int.Parse(Console.ReadLine());
//Quit function
if (n < 0) break;
int[] arr = new int[MAX];
Factorial(arr, n);
Display(arr);
}
//100000 is the max number it can calculate
}
}
}

You have already demonstrated that you know how to use String.PadLeft(), so cache the strings that you are writing in memory so you can inspect them rather than writing directly out to the console.
using System.Linq;
using System.Text;
public static void Display(int[] a)
{
int i = 0;
// build the string in memory, so we can inspect the length of the lines
StringBuilder output = new StringBuilder();
output.Append(a[i]);
for (int j = i - 1, c = 1; j >= 0; j--, c++)
{
output.Append($"{a[j]}".PadLeft(4, '0'));
if (c % 15 == 0)
output.AppendLine();
}
// get the lines into an array so we can normalise the length,
// although we know the length today, calculating it expresses the intent better
var lines = output.ToString().Split(new string [] { Environment.NewLine }, StringSplitOptions.None);
var maxLength = lines.Max(x => x.Length);
// now write the output to the console
foreach(var line in lines)
Console.WriteLine(line.PadLeft(maxLength, ' '));
}
It is not necessary to use StringBuilder like this, you could have used a List<string> and that would simplify the code further. It is however useful to identify that code written targeting the Console can easily be refactored to write to memory via StringBuilder as the syntax is very similar.
You could also have used a StringWriter instance called Console and the syntax would be identical... But that was a step too far for a logic block as simple as this.

Related

I'm generating a list of 100 random "names", now I need to follow it up with 100 more names and 100 random numbers. C#

I'm making a program that generates the "names" (random lines of text from the ASCII) that are the names of movies in this instance. I should follow them up with a "name" of a director for each (can also be generated from the ASCII), and after that the random year that is the year the "movie" was made (from 1896 to 2021).
I have two separate functions that randomize the names of the movies and directors, but I'm confused with the supposed placement of the Console.Writeline which the intelligence only allows inside their own loops. Otherwise it doesn't seem to be able to use the values "directorname" and "moviename".
I need it to write the names in a single line, ai. (KHGTJ, KGHTJF).
Also I need a way to generate a random year from 1896 to 2021 that is printed after the names of the movie, and director, ai. (KFJU, MDDOS, 1922).
private static void GenerateRandomNames()
{
Random random = new Random();
char y = (char)65;
for (int p = 0; p < 100; p++)
{
string directorname = "";
for (int m = 0; m < 5; m++)
{
int b = random.Next(65, 90);
y = (char)b;
directorname += y;
}
Console.WriteLine(directorname);
}
Random rnd = new Random();
char x = (char)65;
for (int j = 0; j < 100; j++)
{
string moviename = "";
for (int i = 0; i < 5; i++)
{
int a = rnd.Next(65, 90);
x = (char)a;
moviename += x;
}
Console.WriteLine(moviename);
}
Console.WriteLine();
I need to fix the plecement of the Console.Writeline() so it can print both names in the same line, and be able to print the year after them.
I've tried placing the Console.Writeline() outside the loops, but of course it can't then use the name. But this way it prints them the wrong way.
If you want to have minimal changes in your code, you can use the following code:
private static void GenerateRandomNames()
{
//a separate thing for the names of the directors (ASCII)
// then for the years they were made (1896-2021)
//they should all be printed in the end ie. (KGMFK, JDBDJ, 1922)
Random rnd = new Random();
char x = (char)65;
for (int j = 0; j < 100; j++)
{
string directors = "";
string moviename = "";
for (int i = 0; i < 5; i++)
{
int a = rnd.Next(65, 90);
x = (char)a;
moviename += x;
}
for (int i = 0; i < 5; i++)
{
int a = rnd.Next(65, 90);
x = (char)a;
directors += x;
}
Console.WriteLine("( "+directors +", "+ moviename + ", " +rnd.Next(1896, 2021).ToString()+" )");
}
Console.WriteLine();
}
and result:
Not sure if it is good to answer this type of question, but answering it anyway.
Since you only want other 5-letter words and 4-digit numbers ranging from 1896 - 2021,
Just get another variable 'b' and do the same as you did for 'a', like :
int b = rnd.Next(65,90) ;
y = char(b) ;
director name += y ;
and to get the year value, you can use this :
year = rnd.Next(1896,2021)
So, by combining all of the above, you have the code like this :
internal class Program
{
private static void GenerateRandomNames()
{
Random rnd = new Random();
char x = (char)65;
char y = (char) 65 ;
for (int j = 0; j < 100; j++)
{
string moviename = "";
string directorName = "";
int year = rnd.Next(1896,2021);
for (int i = 0; i < 5; i++)
{
int a = rnd.Next(65, 90);
int b = rnd.Next(65, 90);
x = (char)a;
moviename += x;
y = (char)a;
directorName += x;
}
Console.WriteLine(moviename);
Console.WriteLine(directorName);
Console.WriteLine(year);
}
Console.WriteLine();
}
static void Main(string[] args)
{
GenerateRandomNames();
}
}
The task becomes easier if you extract the creation of a random name to a new method. This allows you to call it twice easily. I moved the random object to the class (making it a class field), so that it can be reused in different places.
internal class Program
{
private static readonly Random _rnd = new Random();
private static string CreateRandomName(int minLength, int maxLength)
{
string name = "";
for (int i = 0; i < _rnd.Next(minLength, maxLength + 1); i++)
{
char c = (char)_rnd.Next((int)'A', (int)'Z' + 1);
name += c;
}
return name;
}
private static void WriteRandomNames()
{
for (int i = 0; i < 100; i++)
{
string movie = CreateRandomName(4, 40);
string director = CreateRandomName(3, 30);
int year = _rnd.Next(1896, 2022);
Console.WriteLine($"{movie}, {director}, {year}");
}
Console.WriteLine();
}
static void Main(string[] args)
{
WriteRandomNames();
}
}
Note that the second parameter of the Next(Int32, Int32) method is the exclusive upper bound. Therefore I added 1.
output:
HATRHKYAHQTGS, NCPQ, 1999
QVJAYOTTISN, LJTGJDMB, 2018
JEXJDICLRMZFRV, GJPZHFBHOTR, 1932
SKFINIGVYUIIVBD, DIZSKOS, 1958
LWWGSEIZT, AMDW, 1950
OAVZVQVFPPBY, SPEZZE, 2008
YLNTZZIXOCNENGYUL, URNJMK, 1962
ONIN, WUITIL, 1987
RJUXGORWDVQRILDWWKSDWF, MOEYPZQPV, 1946
YUQSSOPZTCTRM, UEPPXIVGERG, 1994
KILWEYC, QJZOTLKFMVPHUE, 1915
Wow, in the time it took me to write an answer, three or more others appeared. They all seem like pretty good answers to me, but since I went to the trouble of writing this code, here you go. :)
I focused on using the same Random in different ways, because I think that's what you were asking about.
using System;
using System.Collections.Generic;
using System.Linq;
Random rnd = new Random(1950);
GenerateRandomNames();
void GenerateRandomNames()
{
for (int j = 0; j < 100; j++)
{
// here's one way to get a random string
string name = Guid.NewGuid().ToString().Substring(0, 5);
string description = new string(GetRandomCharacters(rnd.Next(5,16)).ToArray());
string cleaner = new string(GetCleanerCharacters(rnd.Next(5, 16)).ToArray());
string preferred = new string(GetPreferredRandomCharacters(rnd.Next(5, 16)).ToArray());
int year = rnd.Next(1896, DateTime.Now.Year + 1);
Console.WriteLine($"{year}\t{preferred}");
Console.WriteLine($"{year}\t{cleaner}");
Console.WriteLine($"{year}\t{name}\t{description}");
Console.WriteLine();
}
Console.WriteLine();
}
// Not readable
IEnumerable<char> GetRandomCharacters(int length = 5)
{
for (int i = 0; i < length; i++)
{
yield return Convert.ToChar(rnd.Next(0, 255));
}
}
// gives you lots of spaces
IEnumerable<char> GetCleanerCharacters(int length = 5)
{
for (int i = 0; i < length; i++)
{
char c = Convert.ToChar(rnd.Next(0, 255));
if (char.IsLetter(c))
{
yield return c;
}
else
{
yield return ' ';
}
}
}
// Most readable (in my opinion), but still nonsense.
IEnumerable<char> GetPreferredRandomCharacters(int length = 5)
{
for (int i = 0; i < length; i++)
{
bool randomSpace = rnd.Next(0, 6) == 3;
if (i > 0 && randomSpace) // prevent it from starting with a space
{
yield return ' ';
continue;
}
var c = Convert.ToChar(rnd.Next(65, 91)); // uppercase letters
if (rnd.Next(0, 2) == 1)
{
c = char.ToLower(c);
}
yield return c;
}
}

How can I stop 0 from appearing in my array

So I have a method which returns an array of the factors of a number
Tools.cs
public static long[] GetFactors(long number)
{
long range = number / 2;
long potentialFactors = 2;
long[] factors = new long[range + 1];
factors[0] = 1;
factors[range] = number;
for (long i = 1; i < range; i++)
{
if (number % potentialFactors == 0)
{
factors[i] = potentialFactors;
potentialFactors++;
} else
{
potentialFactors++;
}
}
Console.WriteLine($"here are the factors for the number {number}:\n"+string.Join("\n", factors));
return factors;
}
program.cs
static void Main(string[] args)
{
Tools.GetFactors(24);
Console.ReadLine();
}
But when I run my code, this appears:
here are the factors for the number 24:
1
2
3
4
0
6
0
8
0
0
0
12
24
How can I stop 0 from appearing, should I rewrite the "for" loop, or is there a way to remove 0 from the array?
You are allocating a fixed size array and setting the element to non-zero only when it is a factor.
You should instead use a var factors = new List<long>(); and call factors.Add(potentialFactor); to only store those numbers which are valid factors.
This code is using List instead of Array and also there are some other changes.
public static List<long> GetFactors(long number)
{
long range = number / 2;
List<long> factors = new List<long>() { 1 };
for (long i = 2; i <= range; i++)
{
if (number % i == 0)
{
factors.Add(i);
}
}
factors.Add(number);
Console.WriteLine($"here are the factors for the number {number}:\n" + string.Join("\n", factors));
return factors;
}
I agree a list is better when you dont know before hand how many factors you will gote. But if you really want to use an Array. You can loop throught this array, find the 0's one by one and them swith Left the numbers. Like so :
// Extension Method of array
public static void RemoveAllZeros(this long[] array) // O(N^2)
{
for (int i = 0; i < array.Length; i++)
{
if (array[i] == 0)
{
// Grab the index override value and continue swift left
for (int j = i; j < array.Length - 1; j++)
{
array[j] = array[j + 1];
}
}
}
}
OR using a bit of LINQ and List :p :
// Extension Method of array
public static void RemoveAllZeros(this long[] numbers)
{
int zeroPst = numbers.ToList().IndexOf(0);
if (zeroPst == -1)
return;
for (int i = zeroPst; i < numbers.Length - 1; i++)
{
numbers[i] = numbers[i + 1];
}
numbers.RemoveAllZeros(); //Recursion, carefull
}

Integer to alphabet string (a, A, b, B, ..., z, Z, aa, Aa, ba, Ba, ... za, zA, aA, AA, ...)

I found a code to get a different output, but it could be a hint for a solution.
public string GetCode(int number)
{
int start = (int)'A' - 1;
if (number <= 26) return ((char)(number + start)).ToString();
StringBuilder str = new StringBuilder();
int nxt = number;
List<char> chars = new List<char>();
while (nxt != 0) {
int rem = nxt % 26;
if (rem == 0) rem = 26;
chars.Add((char)(rem + start));
nxt = nxt / 26;
if (rem == 26) nxt = nxt - 1;
}
for (int i = chars.Count - 1; i >= 0; i--) {
str.Append((char)(chars[i]));
}
return str.ToString();
}
The output for this method is
A
B
C
(...)
Z
AA
AB
AC
(...)
AZ
AAA
(...)
I would like to achieve slightly different output, stated in the title. What would be the most efficient solution for it?
Rather than get code for each number it is more efficient just to count. So my code is counting to 52 (a-zA-Z) and then ripple and adding one to next 52 Place (just like decimal counting where you get to 10 and then add one to next place). See code below
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
new RipleCount52(10000);
}
}
public class RipleCount52
{
//places are a number from 0 t0 51 indicating each of the 52 charaters
//the least significant place is index 0
//when printing character the order has to be reversed so most significant place gets printed first.
public List<int> places = new List<int>();
public RipleCount52(int maxNumber)
{
int count = 0;
places.Add(count);
for (int i = 0; i < maxNumber; i++)
{
string output = string.Join("",places.Reverse<int>().Select(x => (x < 26) ? (char)((int)'a' + x) : (char)((int)'A' + x - 26)));
Console.WriteLine(output);
places[0] += 1;
//riple after all 52 letter are printed
if (count++ == 51)
{
Ripple();
count = 0;
}
}
}
private void Ripple()
{
//loop until no ripple is required
for (int i = 0; i < places.Count(); i++)
{
if (places[i] == 52)
{
//all places rippled a new place needs to be added
if (i == places.Count - 1)
{
places[i] = 0;
places.Insert(0, 0);
break;
}
}
else
{
//no more ripples are required so exit
places[i] += 1;
break;
}
places[i] = 0;
}
}
}
}

HeapSort Algorythm from txt file to list of arrays doesn't Sort the numbers

So I have to make HeapSort Algorythm for University using pseudocode I was given (only for heapsort). And I have to use input and output file. But for now I have only made input file which is working fine since it loads the txt file and writes down all the numbers in Console. So the problem is that after adding sorting methods to Main nothing changes. Also I decided to make a test for every method and all of them writes down my numbers once and that is it. I am not really good with sorting so it is hard for me to find the issue. Also because it is from pseudocode I had to use and no the code I could do for myself. So Do You know what cause thats issue that the sorting doesn't occure?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Win32;
using System.IO;
using System.Windows.Forms;
namespace Zad4
{
class Program
{
void Heapify(List<int> array, int i, int n)
{
int largest, temp;
int parent = i;
int left = 2 * i + 1;
int right = 2 * i + 2;
if (left < n && array[left] > array[parent])
{
largest = left;
}
else
{
largest = parent;
}
if (right < n && array[right] > array[largest])
{
largest = right;
}
if (largest != i)
{
temp = array[i];
array[i] = array[largest];
array[largest] = temp;
Heapify(array, largest, n);
}
}
void BuildHeap(List<int> array, int n)
{
int i;
for (i = (n - 1) / 2; i >= 0; i--)
{
Heapify(array, i, n);
}
}
void HeapSort(List<int> array, int n)
{
int i, temp;
for (i = n - 1; i >= 0; i--)
{
temp = array[0];
array[0] = array[n - 1];
array[n - 1] = temp;
n = n - 1;
Heapify(array, 0, n);
Console.WriteLine(string.Join(" ", array));
}
}
static void Main(string[] args)
{
int n = 0;
Program A = new Program();
StreamReader myFile =
new StreamReader("C:\\Users\\dawid\\Desktop\\C#\\Heapsort\\dane.txt");
string myString = myFile.ReadToEnd();
myFile.Close();
char rc = (char)10;
String[] listLines = myString.Split(rc);
List<List<int>> listArrays = new List<List<int>>();
for (int i = 0; i < listLines.Length; i++)
{
List<int> array = new List<int>();
String[] listInts = listLines[i].Split(' ');
for (int j = 0; j < listInts.Length; j++)
{
if (listInts[j] != "\r")
{
array.Add(Convert.ToInt32(listInts[j]));
}
}
listArrays.Add(array);
A.BuildHeap(array, n);
A.HeapSort(array, n);
}
foreach (List<int> array in listArrays)
{
foreach (int i in array)
{
Console.WriteLine(string.Join(" ", array));
}
}
Console.WriteLine();
Console.ReadLine();
}
}
}
So the solution I found is just changing the way I read my txt file and the most important one was bad use of my methods. So that is how it looks now and it sorting well. Maybe I shouldn't ask a question since I got an answer on my own. But well. There You go:
static void Main(string[] args)
{
Program A = new Program();
string[] array = System.IO.File.ReadAllLines(#"C:\Users\dawid\Desktop\C#\Heapsort\dane.txt");
int[] arrayInt = Array.ConvertAll(array, int.Parse);
A.BuildHeap(arrayInt, arrayInt.Length);
A.HeapSort(arrayInt, arrayInt.Length);
Console.WriteLine(string.Join(" ", arrayInt));
Console.ReadLine();
}

How can define a 26x2 array and then use LINQ on its rows?

Grrrr I have C# and multidimensional arrays. For some reason, coming from a C/C++ background, they really annoy me.
So when I run
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
class Solution
{
static void Main(String[] args)
{
int T = Int32.Parse(Console.ReadLine());
for(int t = 0; t < T; ++t)
{
string str = Console.ReadLine();
if(str.Length % 2 == 1)
{
Console.WriteLine(-1);
continue;
}
int n = str.Length / 2;
// determine how many replacements s1 needs to be an anagram of s2
string s1 = str.Substring(0, n);
string s2 = str.Substring(n, n);
int[][] counter = new int[26][2];
int ascii_a = (int)'a';
for(int i = 0; i < n; ++i)
{
counter[(int)s1[i] - ascii_a][0] += 1;
counter[(int)s2[i] - ascii_a][1] += 1;
}
int count = counter.Select((pair => Math.Abs(pair[0] - pair[1]))).Sum();
Console.WriteLine(count);
}
}
}
I get
solution.cs(22,42): error CS0029: Cannot implicitly convert type int'
toint[][]' Compilation failed: 1 error(s), 0 warnings
No idea why.
I can change it to
int[,] counter = new int[26,2];
int ascii_a = (int)'a';
for(int i = 0; i < n; ++i)
{
counter[(int)s1[i] - ascii_a, 0] += 1;
counter[(int)s2[i] - ascii_a, 1] += 1;
}
int count = counter.Select((pair => Math.Abs(pair[0] - pair[1]))).Sum();
but then, of course, my LINQ statement breaks.
If you change
int[][] counter = new int[26][2];
to
int[][] counter = new int[26][];
for (int i = 0; i < counter.Length; i++)
counter[i] = new int[2];
code compiles. You can test the rest as you like. As you haven't provided necessary input in OP.
You can't define jagged array like that:
int[][] counter = new int[26][2];
I recommend reading on jagged arrays:
https://msdn.microsoft.com/en-us/library/2s05feca.aspx
https://msdn.microsoft.com/en-us/library/2yd9wwz4.aspx
In your case I'd suggest using not jagged, but multi-dimentional array:
var counter = new int[26,2];
What you are using here is a jagged array, and you can't new one like that:
int[][] counter = new int[26][2];
You have to declare the inner array separately :
int[][] counter = new int[26][];
for (int i = 0; i < 26; i++)
{
counter[i] = new int[2];
}
Alternatively, as #IvanStoev suggested, you can also use a LINQ one liner:
var counter = Enumerable.Range(0, 26).Select(_ => new int[2]).ToArray();
You can also use a 2-dimensional array, such as this one :
// notice there is only one bracket
int[,] counter = new int[26,2];
int ascii_a = (int)'a';
for(int i = 0; i < n; ++i)
{
counter[(int)s1[i] - ascii_a, 0] += 1;
counter[(int)s2[i] - ascii_a, 1] += 1;
}
// and, you will need to update your query,
// as linq would implicitly flatten the array
var count = Enumerable.Range(0, 26)
.Select(x => counter[x, 0] - counter[x, 1])
.Sum();
I would suggest defining a Counter struct then use an array of those instead of a multi-dimensional array.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
class Solution
{
struct Counter
{
public int c1;
public int c2;
}
static void Main(String[] args)
{
int T = Int32.Parse(Console.ReadLine());
for (int t = 0; t < T; ++t)
{
string str = Console.ReadLine();
if (str.Length % 2 == 1)
{
Console.WriteLine(-1);
continue;
}
int n = str.Length / 2;
// determine how many replacements s1 needs to be an anagram of s2
string s1 = str.Substring(0, n);
string s2 = str.Substring(n, n);
Counter[] counter = new Counter[26];
int ascii_a = (int)'a';
for (int i = 0; i < n; ++i)
{
counter[(int)s1[i] - ascii_a].c1 += 1;
counter[(int)s2[i] - ascii_a].c2 += 1;
}
int count = counter.Select((pair => Math.Abs(pair.c1 - pair.c2))).Sum();
Console.WriteLine(count);
}
}
}

Categories

Resources