I'm trying to create a function which will return string in Triangle Sine-Wave format:
but currently, my format is only in Wave format:
Code below:
public static void printWave(string str)
{
int height = 3;
// Get length of the string
int len = str.Length;
// Create a 2d character array
char[,] matrixArray = new char[height, len];
char[] charArray = str.ToCharArray();
// for counting the
// rows of the ZigZag
int row = 0;
bool down = true;
for (int i = 0; i < len; i++)
{
// put characters
// in the matrix
matrixArray[row, i] = charArray[i];
// You have reached the bottom
if (row == height - 1)
down = false;
else if (row == 0)
down = true;
if (down)
row++;
else
row--;
}
// Print the Zig-Zag String
for (int i = 0; i < height; i++)
{
for (int j = 0; j < len; j++)
{
Console.Write(matrixArray[i, j] + " ");
}
Console.Write("\n");
}
}
Can you please help me modify my code to it will return triangle sin wave format?
We can use 3 separate StringBuilders to append to depending on our boolean top and a simple even value comparison. A quick TL;DR is that anything at an even index goes in the middle row, and then we flip between appending to the top or bottom row:
public static void printWave(string str)
{
//for use to determine top or bottom StringBuilder
bool top = true;
//will be used to generate each row of the output
StringBuilder topString = new StringBuilder();
StringBuilder middleString = new StringBuilder();
StringBuilder bottomString = new StringBuilder();
//iterate through paramter string
for (int i = 0; i < str.Length; i++)
{
//if char is at an even index, it goes in the middle StringBuilder, blank spaces in top and bottom builders
if (i%2 == 0)
{
topString.Append(" ");
middleString.Append(str[i]);
bottomString.Append(" ");
}
//if not even index, determine top or bottom row
else
{
//simply check our boolean and then flip it after use
if (top)
{
topString.Append(str[i]);
middleString.Append(" ");
bottomString.Append(" ");
top = false;
}
else
{
topString.Append(" ");
middleString.Append(" ");
bottomString.Append(str[i]);
top = true;
}
}
}
//write each row of strings on new lines
Console.WriteLine(topString.ToString());
Console.WriteLine(middleString.ToString());
Console.WriteLine(bottomString.ToString());
}
For a variable height:
public static void printWave(string str)
{
//height we want the wave to reach
int height = 5;
//determine "middle" row
int startingRow = height / 2;
int currentRow = startingRow; //this one is for modifying inside loop
bool up = true;
//2D array to hold the rows
char[,] arr = new char[height, str.Length];
for (int i = 0; i < str.Length; i++)
{
for (int j = 0; j < height; j++)
{
if (j == currentRow)
{
arr[j, i] = str[i];
}
else
arr[j, i] = ' ';
}
//could probably break this into more digestible pieces if time to think about it
if (up)
{
if (currentRow == 0)
{
up = false;
currentRow++;
}
else
{
currentRow--;
}
}
else
{
if (currentRow == height - 1)
{
up = true;
currentRow--;
}
else
{
currentRow++;
}
}
}
for (int k = 0; k < height; k++)
{
for (int l = 0; l < str.Length; l++)
{
Console.Write(arr[k, l]);
}
Console.WriteLine();
}
}
Examples of height = 5 and height = 6 output:
And finally, height = 7
This version works, but it's hard-coded to just the 3 rows like the question shows. If larger waves are needed, or especially if the size of the wave depends on the input string, then this may be hard to adjust to the requirements.
public static void PrintWave(string str)
{
printWithRowLogic(str, (i) => (i - 1) % 4 == 0);
Console.WriteLine();
printWithRowLogic(str, (i) => i % 2 == 0);
Console.WriteLine();
printWithRowLogic(str, (i) => (i - 3) % 4 == 0);
}
private static void printWithRowLogic(string str, Func<int, bool> checkLogic)
{
for (int i = 0; i < str.Length; i++)
Console.Write(checkLogic(i) ? str[i] : ' ');
}
So, i have this frankenstein:
var unsorted = new List<(Hand, List<Card>)>();
And when I try to add smt like this:
unsorted.Add((hand, _tempList));
I receive and error
Index was out of range. Must be non-negative and less than the size of the collection. (Parameter 'index')
How to properly initialize this List if I do not know in advance how many items will be stored?
at the request of comments:
_tempList = IsStraightFlush(theValueHand);
if (_tempList.Count == 5)
{
unsorted.Add((hand, _tempList));
continue;
}
A function from where i add a List to the Tuple
private List<Card> IsStraightFlush(List<Card> hList)
{
var st = 0;
_tempList.Clear();
foreach (var t in hList)
{
...
}
if (_tempList.Count < 5)
{
return new List<Card>();
}
hList = _tempList.ToList();
_tempList.Clear();
for (var i = 0; i < hList.Count - 2; i++)
{
...
if (st == 4)
{
_tempList.Add(hList[i + 1]);
return _tempList;
}
}
st = 0;
_tempList.Clear();
if (hList[0].Value == 13) //Ace through 5
for (int i = hList.Count - 1, j = 0; i > 0; i--, j++)
{
...
if (st == 4)
{
_tempList.Add(hList.First());
return _tempList.OrderBy(x => x.Value).ToList();
}
}
return new List<Card>();
}
And when i use it
resultHands.AddRange(SortStraightFlushes(unsorted));
...
private List<(int, Hand)> SortStraightFlushes(List<(Hand, List<Card>)> hList)
{
var sortedHList = hList.OrderBy(x => x.Item2[0].Value).ToList();
List<(int, Hand)> output = new List<(int, Hand)>();
for (int i = 0; i < sortedHList.Count; i++)
{
if(i != sortedHList.Count - 1)
if (sortedHList[i].Item2[0].Value == sortedHList[i + 1].Item2[0].Value)
output.Add((1, sortedHList[i].Item1));
else
output.Add((0, sortedHList[i].Item1));
else
output.Add((0, sortedHList[i].Item1));
}
return output;
}
I don't know how beautiful and accurate it is, but it all worked out the way it did:
unsorted.Add((hand, new List<Card>().Concat(_tempList).ToList()));
I am having trouble editing the values of a 2d char array.
char[,] chrRaster = new char[4, 5];
After adding values to the array and printing it to the console, I get:
// Input example:
*****
**.**
*****
****.
I am trying to make an algorithm that replaces every '*' that is beside, under or above a '.' by a '.' and then printing this to the console.
// Output after algorithm example:
**.**
*...*
**.*.
***..
I have tried converting the 2d char array to a 2d string array and then using IndexOf('*') to replace every '*' that is beside, under or above a '.', and I also tried calculating this using a number of if and for loops without any luck.
static void Main(string[] args)
{
// Variablen
int intTestgeval = 0; // Number of times you want program to repeat
int intN = 0; // Number of rows
int intM = 0; // Number of coloms
char chrGrond; // Used to store '*' or '.'
char[,] chrRaster; // 2d char array used to store all values
// Code
try
{
intTestgeval = Int32.Parse(Console.ReadLine()); // Number of times program will repeat
if(intTestgeval > 150) // Program can not repeat more then 150 times
{
throw new Exception();
}
}
catch (Exception)
{
Environment.Exit(0);
}
intN = Controle(intN); // Number of rows ophalen
intM = Controle(intM); // Number of Coloms ophalen
chrRaster = new char[intN, intM]; // Initializing array with user input
for (int intR = 0; intR < intTestgeval; intR++) // Print 2d array to console
{
for(int intY = 0; intY < intN; intY++)
{
for(int intZ = 0; intZ < intM; intZ++)
{
chrGrond = Convert.ToChar(Console.ReadKey().KeyChar);
chrRaster[intY, intZ] = chrGrond;
}
Console.WriteLine();
}
instorten[intR] = Instorten(chrRaster, intN, intM); // Ignore this part, that's another part of my assignment not related to my question.
}
}
static int Controle( int intX )
{
try
{
intX = Int32.Parse(Console.ReadLine());
if (intX > 150 || intX < 1) // Length of row and colom can not exceed 20 and can not go lower then 1
{
throw new Exception();
}
return intX;
}
catch // Program will off if value does not meet requirements
{
Environment.Exit(0);
return intX;
}
}
// It is this part of the program I need help with. This is what I tried but can't get any further
static int Instorten(char[,] chrRaster, int intN, int intM)
{
for (int intY = 0; intY < intN; intY++)
{
for (int intZ = 0; intZ < intM; intZ++)
{
if(chrRaster[intY, intZ] == '.' && chrRaster[intY, intZ + 1] == '*' || chrRaster[intY, intZ] == '*' && chrRaster[intY, intZ + 1] == '.')
{
}
}
Console.WriteLine();
}
int intm = 0;
return intm;
}
}
One way to do this would be to make a copy of the array and then iterate over it, examining each item. If the item is a '.', then update the neighbors of this item in the original array.
To determine the neighbors, we simply add one to the row to get the neighbor below, subtract one from the row to get the neighbor above, and similarly we can get the right and left neighbors by adding/subtracting from the column value. Of course we need to ensure that we're inside the bounds of the array before doing anything.
We could write a method with this logic that might look like:
private static void ExposeDotNeighbors(char[,] input)
{
if (input == null) return;
// Make a copy of the input array that we can iterate over
// so that we don't analyze items that we've already changed
var copy = (char[,]) input.Clone();
for (var row = 0; row <= copy.GetUpperBound(0); row++)
{
for (var col = 0; col <= copy.GetUpperBound(1); col++)
{
if (copy[row, col] == '.')
{
// Update neighbors in original array
// Above = [row - 1, col], Below = [row + 1, col],
// Left = [row, col - 1], Right = [row, col + 1]
// Before updating, make sure we're inside the array bounds
if (row > 0) input[row - 1, col] = '.';
if (row < input.GetUpperBound(0)) input[row + 1, col] = '.';
if (col > 0) input[row, col - 1] = '.';
if (col < input.GetUpperBound(1)) input[row, col + 1] = '.';
}
}
}
}
We can also write some helper methods that will give us the initial array and to print an array to the console (also one that will write a header to the console):
private static char[,] GetInitialArray()
{
var initialArray = new char[4, 5];
for (var row = 0; row <= initialArray.GetUpperBound(0); row++)
{
for (var col = 0; col <= initialArray.GetUpperBound(1); col++)
{
if ((row == 1 && col == 2) || (row == 3 && col == 4))
{
initialArray[row, col] = '.';
}
else
{
initialArray[row, col] = '*';
}
}
}
return initialArray;
}
private static void PrintArrayToConsole(char[,] input)
{
if (input == null) return;
for (var row = 0; row <= input.GetUpperBound(0); row++)
{
for (var col = 0; col <= input.GetUpperBound(1); col++)
{
Console.Write(input[row, col]);
}
Console.WriteLine();
}
}
private static void WriteHeader(string headerText)
{
if (string.IsNullOrEmpty(headerText))
{
Console.Write(new string('═', Console.WindowWidth));
return;
}
Console.WriteLine('╔' + new string('═', headerText.Length + 2) + '╗');
Console.WriteLine($"║ {headerText} ║");
Console.WriteLine('╚' + new string('═', headerText.Length + 2) + '╝');
}
With these helper methods, we can then write code like:
private static void Main()
{
var chrRaster = GetInitialArray();
WriteHeader("Before");
PrintArrayToConsole(chrRaster);
ExposeDotNeighbors(chrRaster);
WriteHeader("After");
PrintArrayToConsole(chrRaster);
GetKeyFromUser("\nDone! Press any key to exit...");
}
And out output would look like:
I noticed that you also appear to be getting the values from the user, and using try/catch blocks to validate the input. A better approach might be to write a helper method that takes in a string that represents the "prompt" to the user, and a validation method that can be used to validate the input. With this, we can keep asking the user for input until they enter something valid.
Below are methods that get an integer and a character from the user, and allow the caller to pass in a function that can be used for validation. These methods will not return until the user enters valid input:
private static char GetCharFromUser(string prompt, Func<char, bool> validator = null)
{
char result;
var cursorTop = Console.CursorTop;
do
{
ClearSpecificLineAndWrite(cursorTop, prompt);
result = Console.ReadKey().KeyChar;
} while (!(validator?.Invoke(result) ?? true));
Console.WriteLine();
return result;
}
private static int GetIntFromUser(string prompt, Func<int, bool> validator = null)
{
int result;
var cursorTop = Console.CursorTop;
do
{
ClearSpecificLineAndWrite(cursorTop, prompt);
} while (!int.TryParse(Console.ReadLine(), out result) ||
!(validator?.Invoke(result) ?? true));
return result;
}
private static void ClearSpecificLineAndWrite(int cursorTop, string message)
{
Console.SetCursorPosition(0, cursorTop);
Console.Write(new string(' ', Console.WindowWidth));
Console.SetCursorPosition(0, cursorTop);
Console.Write(message);
}
We can then re-write our GetInitialArray method to use these methods to get the dimensions and values from the user:
private static char[,] GetInitialArray()
{
const int maxCols = 20;
const int maxRows = 20;
var numCols = GetIntFromUser(
$"How many columns do you want (1 - {maxCols}): ",
i => i > 0 && i <= maxCols);
var numRows = GetIntFromUser(
$"How many rows do you want (1 - {maxRows}): ",
i => i > 0 && i <= maxRows);
var initialArray = new char[numRows, numCols];
for (var row = 0; row <= initialArray.GetUpperBound(0); row++)
{
for (var col = 0; col <= initialArray.GetUpperBound(1); col++)
{
initialArray[row, col] = GetCharFromUser(
$"Enter value for [{row}, {col}] ('.' or '*'): ",
c => c == '.' || c == '*');
}
}
return initialArray;
}
And now our output might look like this:
If you try it, notice that you cannot enter an illegal value. The program just waits for you to read the instructions and enter a valid number or character. :)
Here is the algorithm that does what you want. I have tried to explain my code in the comments. The output will match what you're looking for.
static void Main(string[] args)
{
char STAR = '*';
char DOT = '.';
var input = new char[,]
{
{ STAR,STAR,STAR,STAR,STAR},
{ STAR,STAR,DOT,STAR,STAR},
{ STAR,STAR,STAR,STAR,STAR},
{ STAR,STAR,STAR,STAR,DOT}
};
var output = new char[4, 5];
// Copy each from input to output, checking if it touches a '.'
for (int x = 0; x < 4; x++)
{
for (int y = 0; y < 5; y ++)
{
if (input[x, y] == STAR)
{
var isDot = false;
// Check left
if (x > 0)
isDot = input[x - 1, y] == DOT;
// Check right
if (x < 3)
isDot = isDot || (input[x + 1, y] == DOT);
// Check above
if (y > 0)
isDot = isDot || (input[x, y - 1] == DOT);
// Check below
if (y < 4)
isDot = isDot || (input[x, y + 1]) == DOT;
output[x, y] = isDot ? DOT : STAR;
}
else
{
output[x, y] = input[x, y];
}
}
}
// Print output
for (int x = 0; x < 4; x ++)
{
for (int y = 0; y < 5; y ++)
{
Console.Write(output[x, y]);
}
Console.WriteLine();
}
Console.Read();
}
You can go like this :
using System;
public class chars
{
public static void Main(string[] args)
{
char[,] charArray = new char[,] {{'*','*','*','*','*'},
{'*','*','.','*','*'},
{'*','*','*','*','*'},
{'*','*','*','*','.'}};
int[,] holdIndex = new int[4, 5];
for(int i = 0; i<4; i++) // get allindexes containing '.'
{
for(int j = 0; j<5; j++)
{
if(charArray[i,j] == '.')
holdIndex[i,j] = 1;
else
holdIndex[i,j] = 0;
}
}
for(int i = 0; i<4; i++)
{
for(int j = 0; j<5; j++)
{
if(holdIndex[i,j] == 1)
{
if(i!=0)
charArray[i-1,j] = '.'; //up
if(j!=0)
charArray[i,j-1] = '.'; // left
if(j!=4)
charArray[i,j+1] = '.'; //right
if(i!=3)
charArray[i+1,j] = '.'; //down
}
}
}
for(int i = 0; i<4; i++)
{
for(int j = 0; j<5; j++)
{
Console.Write(charArray[i,j]);
}
Console.WriteLine();
}
Console.Read();
}
}
How can I add additional 30 character from the char that matches where in my code below.
private void CheckGarbageCharacters(string input)
{
var contentList = File.ReadAllLines(input).ToList();
int[] lineno = { 0 };
foreach (var line in contentList)
{
lineno[0]++;
foreach (var errorModel in from c in line
where c > '\u007F'
select new ErrorModel
{
Filename = Path.GetFileName(input),
LineNumber = lineno[0],
ErrorMessage = "Garbage character found.",
Text = c.ToString()
})
{
_errorList.Add(errorModel);
}
}
}
I'm not sure I fully understand your question but based on the code you have provided it seems like you are trying to do something like this...
~ Pseudo Code ~ This has not been tested ~
private void CheckGarbageCharacters(string filename)
{
var lines = File.ReadAllLines(filename).ToList();
for (int i = 0; i < lines.Count; i++)
{
var line = lines[i];
for (int j = 0; j < line.Length; j++)
{
var c = line[j];
if (c > '\u007F')
{
// Grab the next 30 characters after 'c'
var text = c.ToString();
for (int k = 0; k < 30; k++)
{
if ((j + k) > (line.Length - 1))
{
break;
}
text += line[j + k].ToString();
}
// Create the error message
var error = new ErrorModel()
{
Filename = Path.GetFileName(filename),
LineNumber = i,
ErrorMessage = "Garbage character found.",
Text = text
};
// Add the error to the list
_errorList.Add(error);
}
}
}
}
I'm not sure what you mean by "add additional 30 characters from the char that matches where in my code" though.
EDIT
I've updated my answer according to the information you've provided in the comments. I believe this is what you are trying to do here.
I am solving the same problem as here Project Euler #22 Python, 2205 points missing?, but I am using C#. I can't find the mistake. Here is my code:
class Program
{
static List<string> pole;
static string SaveName(StreamReader reader)
{
int znak = reader.Read();
string jmeno = "";
while ((znak < 'A') || (znak > 'Z'))
{
znak = reader.Read();
}
while (znak != ',')
{
jmeno = jmeno + (char) znak;
znak = reader.Read();
if (znak == 34) break;
}
return jmeno;
}
static void SaveNamesIntoList()
{
StreamReader reader = new StreamReader(#"../../../names.txt");
while (reader.Read() != ';')
{
pole.Add(SaveName(reader));
}
}
static void Main(string[] args)
{
pole = new List<string>();
SaveNamesIntoList();
pole.Sort();
int sum = 0;
int sum_word = 0;
string name = "";
for (int i = 0; i < pole.Count; i++)
{
name = pole[i];
sum_word = 0;
for (int u = 0; u < name.Length; u++)
{
sum_word += (name[u] - 'A' + 1);
}
sum += (sum_word * (i+1));
}
Console.WriteLine(sum);
}
}
Thanks for any answer:)
Ther reason why you have different result is than Czech language has specific letter 'CH' whitch is after 'H' so in alfabetical order without using right culture you can have sometring like this
aaa
bbb
ccc
czz
ddd
cha
There are a few issues here. You don't check if the reader reached the end of stream - you have to check if the Read returned -1. If it did - it's the end of the file. On top of that, you don't dispose the reader...
Then, as Cedric noted in the comments, you haven't really sorted the list, hence the result is wrong even after changing it to:
using (var reader = new StreamReader("names.txt"))
{
while (reader.Read() != -1)
{
pole.Add(SaveName(reader));
}
}
What you need to do is add this line (which is a bit wasteful in general, but I'll get to that in a sec):
pole = pole.OrderBy(x => x).ToList(); //<<----- this one
for (int i = 0; i < pole.Count; i++)
{
name = pole[i];
sum_word = 0;
for (int u = 0; u < name.Length; u++)
{
sum_word += (name[u] - 'A' + 1);
}
sum2 += (sum_word*(i + 1));
}
And the result is 871198282, which should be correct - at least that's what the people are saying in the linked question.
Even then, might I suggest an easier way of solving that whole problem:
var scores = Enumerable.Range('A', 'Z' - 'A' + 1)
.Select((i, ch) => new { Character = (char) i, Weight = ch + 1 })
.ToDictionary(key => key.Character, val => val.Weight);
var sum = File.ReadAllText("names.txt")
.Split(',')
.Select(x => x.Trim('"'))
.OrderBy(x => x)
.Select((x, i) => (i + 1)*x.Select(y => scores[y]).Sum())
.Sum();
Here's a version using Linq.
void Main()
{
var file = #"C:\...location.of.file...\p022_names.txt";
using (var reader = new StreamReader(file, Encoding.UTF8))
{
NameScore(reader.ReadToEnd().Replace("\"",string.Empty).Split(new[]{','})).Dump();
}
}
private long NameScore(string[] names)
{
return names.OrderBy(o => o)
.Select((l, i) => { return l.ToUpper().ToCharArray().Sum(s => (int)s - 64) * (i + 1);})
.Sum(s => s);
}