Compare lexicographically two char arrays - c#

Can you help with this?
I need to compare lexicographically two arrays: if one of them is shorter than other, it is lexicographically first. If their length are same, they had to be compared element by element. If an element is before the other in the alphabet, this array is lexicographically first.
Here is my code:
using System;
internal class CompareTwoCharArraysLexicographically
{
private static void Main()
{
char[] firstArray = {'a', 'b', 'c', 'z'};
int firstArrayLength = firstArray.Length;
char[] secondArray = {'a', 'b', 'c', 'd'};
int secondArrayLength = secondArray.Length;
int length = Math.Min(firstArray.Length, secondArray.Length);
if (firstArray.Length > secondArray.Length)
{
Console.WriteLine("Second array is earlier.");
}
else if (firstArray.Length == secondArray.Length)
{
for (int i = 0; i < length; i++)
{
if (firstArray[i] > secondArray[i])
{
Console.WriteLine("2 array is earlier.");
break;
}
else if (secondArray[i] > firstArray[i])
{
Console.WriteLine("1 array is earlier.");
break;
}
else
{
Console.WriteLine("Two arrays are equal.");
}
}
}
else
{
Console.WriteLine("First array is earlier.");
}
}
}
How I can avoid three time repeated message "Two arrays are equal."?

Yet another structured way to do it:
class LexicographicCharArrayComparer : Comparer<char[]>
{
public override int Compare(char[] x, char[] y)
{
if (x == null || y == null)
return Default.Compare(x, y);
int lengthComp = x.Length.CompareTo(y.Length);
if (lengthComp != 0)
return lengthComp;
return StringComparer.Ordinal.Compare(new string(x), new string(y));
}
}
Usage:
char[] firstArray = { 'a', 'b', 'c', 'z', };
char[] secondArray = { 'a', 'b', 'c', 'd', };
var comparer = new LexicographicCharArrayComparer();
var result = comparer.Compare(firstArray, secondArray);
if (result < 0)
Console.WriteLine("1st array is earlier");
else if (result == 0)
Console.WriteLine("The two arrays are equal");
else
Console.WriteLine("2nd array is earlier");
Your own approach can be repaired, of course. Correct the middle block to something like:
else if (firstArray.Length == secondArray.Length)
{
bool resolved = false;
for (int i = 0; i < length; i++)
{
if (firstArray[i] > secondArray[i])
{
Console.WriteLine("2 array is earlier.");
resolved = true;
break;
}
if (secondArray[i] > firstArray[i])
{
Console.WriteLine("1 array is earlier.");
resolved = true;
break;
}
}
if (!resolved)
{
Console.WriteLine("Two arrays are equal.");
}
}

I think you will need to use a tracking variable to know whether or not the arrays are equal. Currently you are saying they are equal each time two items in the same index are equal. Instead, consider the following code:
else if (firstArray.Length == secondArray.Length)
{
var largerArray = 0;
// Compare each item in the array
for (int i = 0; i < length; i++)
{
// As soon as two items are not equal, set the comparison value and break
if (firstArray[i] > secondArray[i])
{
largerArray = 1;
break;
}
else if (secondArray[i] > firstArray[i])
{
largerArray = 2
break;
}
}
// Check the largerArray value. If it was never changed, the arrays are equal
// Otherwise, display a message based on the value of the largerArray.
if (largerArray == 0)
{
Console.WriteLine("Two arrays are equal.");
}
else
{
Console.WriteLine("{0} array is earlier.", largerArray);
}
}

Here is my suggestion:
Console.Write("Enter a positive number for length of the first array: ");
int n = int.Parse(Console.ReadLine());
Console.Write("Enter a positive number for length of the second array: ");
int m = int.Parse(Console.ReadLine());
// Declare and create the arrays
char[] firstArray = new char[n];
char[] secondArray = new char[m];
Console.WriteLine("Enter values of the arrays: ");
for (int i = 0; i < firstArray.Length; i++)
{
firstArray[i] = char.Parse(Console.ReadLine());
}
Console.WriteLine();
for (int i = 0; i < m; i++)
{
secondArray[i] = char.Parse(Console.ReadLine());
}
Console.WriteLine();
// Print them on the console
for (int i = 0; i < n; i++)
{
Console.Write(" " + firstArray[i]);
}
Console.WriteLine();
for (int i = 0; i < m; i++)
{
Console.Write(" " + secondArray[i]);
}
Console.WriteLine();
int minLength = Math.Min(firstArray.Length, secondArray.Length);
bool equalValues = true;
// Search which of the arrays is lexicographically earlier
for (int i = 0; i < minLength; i++)
{
if (firstArray[i] == secondArray[i])
{
continue;
}
else if (firstArray[i] < secondArray[i])
{
Console.WriteLine("The first array is earlier.");
break;
}
else if (firstArray[i] > secondArray[i])
{
Console.WriteLine("The second array is earlier.");
break;
}
}
for (int i = 0; i < minLength; i++)
{
if (firstArray[i] != secondArray[i])
{
equalValues = false;
}
}
// This is to indicate the values of the two arrays till the element of index minLength-1 are equal
for (int i = 0; i < minLength; i++)
{
if (equalValues && n < m)
{
Console.WriteLine("The first array is earlier.");
break;
}
else if (equalValues && n > m)
{
Console.WriteLine("The second array is earlier.");
break;
}
else if (equalValues && n == m)
{
Console.WriteLine("The two arrays aree equal.");
break;
}
}

Here is a relatively simple implementation using the sums of the ASCII values of the array characters as a lexicographical comparison criteria:
/* Method: compareLexicographically(a, b);
Compare lexicographically the two arrays passed as parameters and print result.
Comparison criteria:
1. Arrays lengths.
2. Accumulated ASCII values of the array characters.
*/
static void compareLexicographically(char[] a, char[] b)
{
if (a.Length == b.Length) // same lengths
{
int suma = 0;
int sumb = 0;
for (int i = 0; i < a.Length; i++)
{
suma += a[i];
sumb += b[i];
}
if (suma == sumb)
{
Console.WriteLine("Two arrays are lexicographically equal.\n");
}
else
{
if (suma < sumb)
{
Console.WriteLine("First array lexicographically smaller than second.\n");
}
else
{
Console.WriteLine("First array lexicographically greater than second.\n");
}
}
}
else // different lengths
{
if (a.Length < b.Length)
{
Console.WriteLine("First array lexicographically smaller than second.\n");
}
else
{
Console.WriteLine("First array lexicographically greater than second.\n");
}
}
}

I think that this fixes your problem :)
Hope I helped you as well u helped me find an answer of an exercise
using System;
internal class CompareTwoCharArraysLexicographically
{
private static void Main()
{
char[] firstArray = { 'a', 'b', 'c', 'z' };
int firstArrayLength = firstArray.Length;
char[] secondArray = { 'a', 'b', 'c', 'd' };
int secondArrayLength = secondArray.Length;
int length = Math.Min(firstArray.Length, secondArray.Length);
bool same = false;
if (firstArray.Length > secondArray.Length)
{
Console.WriteLine("Second array is earlier.");
}
else if (firstArray.Length == secondArray.Length)
{
for (int i = 0; i < length; i++)
{
if (firstArray[i] != secondArray[i])
{
same = false;
if (firstArray[i] > secondArray[i])
{
Console.Clear();
Console.WriteLine("2 array is earlier.");
break;
}
if (secondArray[i] > firstArray[i])
{
Console.Clear();
Console.WriteLine("1 array is earlier.");
break;
}
}
else same = true;
if (same == true)
{
Console.Clear();
Console.WriteLine("Two arrays are equal.");
}
else
{
Console.WriteLine("First array is earlier.");
}
}
}
}
}

Related

C# Console - User inputs X numbers and gets stored in array

I tried to have a console app that takes 5 numbers and fills an array with it but The issue with this code is that, it only accepts 4 numbers and fills the last index with null, how could I fix that?
string[] numbers = new string[4];
Console.WriteLine("Hi, Enter 5 numbers!");
ConsoleKeyInfo key;
for (int i = 0; i < numbers.Length; i++)
{
string _val = "";
do
{
key = Console.ReadKey(true);
if (key.Key != ConsoleKey.Backspace)
{
double val = 0;
bool _x = double.TryParse(key.KeyChar.ToString(), out val);
if (_x)
{
_val += key.KeyChar;
Console.Write(key.KeyChar);
}
}
else
{
if (key.Key == ConsoleKey.Backspace && _val.Length > 0)
{
_val = _val.Substring(0, (_val.Length - 1));
Console.Write("\b \b");
}
}
}
while (key.Key != ConsoleKey.Enter);
Console.WriteLine();
numbers[i] = _val;
}
Console.WriteLine();
for(int i = 0; i < numbers.Length; i++)
{
Console.WriteLine(i + " : " + numbers[i]);
}
Console.WriteLine(numbers.Length);
Console.ReadKey();
}
In the code string[] numbers = new string[4]; means numbers array size is 4 and array starts with 0 index. Hence last index is not null. Change the string[4] to string[5]. Hope this will solve your problem.

Hackerrank: Climbing the Leaderboard

i have a deal with a hackerrank algorithm problem.
It works at all cases, except 6-7-8-9. It gives timeout error. I had spent so much time at this level. Someone saw where is problem?
static long[] climbingLeaderboard(long[] scores, long[] alice)
{
//long[] ranks = new long[scores.Length];
long[] aliceRanks = new long[alice.Length]; // same length with alice length
long lastPoint = 0;
long lastRank;
for (long i = 0; i < alice.Length; i++)
{
lastPoint = scores[0];
lastRank = 1;
bool isIn = false; // if never drop in if statement
for (long j = 0; j < scores.Length; j++)
{
if (lastPoint != scores[j]) //if score is not same, raise the variable
{
lastPoint = scores[j];
lastRank++;
}
if (alice[i] >= scores[j])
{
aliceRanks[i] = lastRank;
isIn = true;
break;
}
aliceRanks[i] = !isIn & j + 1 == scores.Length ? ++lastRank : aliceRanks[i]; //drop in here
}
}
return aliceRanks;
}
This problem can be solved in O(n) time, no binary search needed at all. First, we need to extract the most useful piece of data given in the problem statement, which is,
The existing leaderboard, scores, is in descending order.
Alice's scores, alice, are in ascending order.
An approach that makes this useful is to create two pointers, one at the start of alice array, let's call it "i", and the second is at the end of scores array, let's call it "j". We then loop until i reaches the end of alice array and at each iteration, we check for three main conditions. We increment i by one if alice[i] is less than scores[j] because the next element of alice may be also less than the current element of scores, or we decrement j if alice[i] is greater than scores[j] because we are sure that the next elements of alice are also greater than those elements discarded in scores. The last condition is that if alice[i] == scores[j], we only increment i.
I solved this question in C++, my goal here is to make you understand the algorithm, I think you can easily convert it to C# if you understand it. If there are any confusions, please tell me. Here is the code:
// Complete the climbingLeaderboard function below.
vector<int> climbingLeaderboard(vector<int> scores, vector<int> alice) {
int j = 1, i = 1;
// this is to remove duplicates from the scores vector
for(i =1; i < scores.size(); i++){
if(scores[i] != scores[i-1]){
scores[j++] = scores[i];
}
}
int size = scores.size();
for(i = 0; i < size-j; i++){
scores.pop_back();
}
vector<int> ranks;
i = 0;
j = scores.size()-1;
while(i < alice.size()){
if(j < 0){
ranks.push_back(1);
i++;
continue;
}
if(alice[i] < scores[j]){
ranks.push_back(j+2);
i++;
} else if(alice[i] > scores[j]){
j--;
} else {
ranks.push_back(j+1);
i++;
}
}
return ranks;
}
I think this may help you too:
vector is like an array list that resizes itself.
push_back() is inserting at the end of the vector.
pop_back() is removing from the end of the vector.
Here is my solution with c#
public static List<int> climbingLeaderboard(List<int> ranked, List<int> player)
{
List<int> result = new List<int>();
ranked = ranked.Distinct().ToList();
var pLength = player.Count;
var rLength = ranked.Count-1;
int j = rLength;
for (int i = 0; i < pLength; i++)
{
for (; j >= 0; j--)
{
if (player[i] == ranked[j])
{
result.Add(j + 1);
break;
}
else if(player[i] < ranked[j])
{
result.Add(j + 2);
break;
}
else if(player[i] > ranked[j]&&j==0)
{
result.Add(1);
break;
}enter code here
}
}
return result;
}
Here is a solution that utilizes BinarySearch. This method returns the index of the searched number in the array, or if the number is not found then it returns a negative number that is the bitwise complement of the index of the next element in the array. Binary search only works in sorted arrays.
public static int[] GetRanks(long[] scores, long[] person)
{
var defaultComparer = Comparer<long>.Default;
var reverseComparer = Comparer<long>.Create((x, y) => -defaultComparer.Compare(x, y));
var distinctOrderedScores = scores.Distinct().OrderBy(i => i, reverseComparer).ToArray();
return person
.Select(i => Array.BinarySearch(distinctOrderedScores, i, reverseComparer))
.Select(pos => (pos >= 0 ? pos : ~pos) + 1)
.ToArray();
}
Usage example:
var scores = new long[] { 100, 100, 50, 40, 40, 20, 10 };
var alice = new long[] { 5, 25, 50, 120 };
var ranks = GetRanks(scores, alice);
Console.WriteLine($"Ranks: {String.Join(", ", ranks)}");
Output:
Ranks: 6, 4, 2, 1
I was bored so i gave this a go with Linq and heavily commented it for you,
Given
public static IEnumerable<int> GetRanks(long[] scores, long[] person)
// Convert scores to a tuple
=> scores.Select(s => (scores: s, isPerson: false))
// convert persons score to a tuple and concat
.Concat(person.Select(s => (scores: s, isPerson: true)))
// Group by scores
.GroupBy(x => x.scores)
// order by score
.OrderBy(x => x.Key)
// select into an indexable tuple so we know everyones rank
.Select((groups, i) => (rank: i, groups))
// Filter the person
.Where(x => x.groups.Any(y => y.isPerson))
// select the rank
.Select(x => x.rank);
Usage
static void Main(string[] args)
{
var scores = new long[]{1, 34, 565, 43, 44, 56, 67};
var alice = new long[]{578, 40, 50, 67, 6};
var ranks = GetRanks(scores, alice);
foreach (var rank in ranks)
Console.WriteLine(rank);
}
Output
1
3
6
8
10
Based on the given constraint brute-force solution will not be efficient for the problem.
you have to optimize your code and the key part here is to look up for exact place which can be effectively done by using binary search.
Here is the solution using binary search:-
static int[] climbingLeaderboard(int[] scores, int[] alice) {
int n = scores.length;
int m = alice.length;
int res[] = new int[m];
int[] rank = new int[n];
rank[0] = 1;
for (int i = 1; i < n; i++) {
if (scores[i] == scores[i - 1]) {
rank[i] = rank[i - 1];
} else {
rank[i] = rank[i - 1] + 1;
}
}
for (int i = 0; i < m; i++) {
int aliceScore = alice[i];
if (aliceScore > scores[0]) {
res[i] = 1;
} else if (aliceScore < scores[n - 1]) {
res[i] = rank[n - 1] + 1;
} else {
int index = binarySearch(scores, aliceScore);
res[i] = rank[index];
}
}
return res;
}
private static int binarySearch(int[] a, int key) {
int lo = 0;
int hi = a.length - 1;
while (lo <= hi) {
int mid = lo + (hi - lo) / 2;
if (a[mid] == key) {
return mid;
} else if (a[mid] < key && key < a[mid - 1]) {
return mid;
} else if (a[mid] > key && key >= a[mid + 1]) {
return mid + 1;
} else if (a[mid] < key) {
hi = mid - 1;
} else if (a[mid] > key) {
lo = mid + 1;
}
}
return -1;
}
You can refer to this link for a more detailed video explanation.
static int[] climbingLeaderboard(int[] scores, int[] alice) {
int[] uniqueScores = IntStream.of(scores).distinct().toArray();
int [] rank = new int [alice.length];
int startIndex=0;
for(int j=alice.length-1; j>=0;j--) {
for(int i=startIndex; i<=uniqueScores.length-1;i++) {
if (alice[j]<uniqueScores[uniqueScores.length-1]){
rank[j]=uniqueScores.length+1;
break;
}
else if(alice[j]>=uniqueScores[i]) {
rank[j]=i+1;
startIndex=i;
break;
}
else{continue;}
}
}
return rank;
}
My solution in javascript for climbing the Leaderboard Hackerrank problem. The time complexity of the problem can be O(i+j), i is the length of scores and j is the length of alice. The space complexity is O(1).
// Complete the climbingLeaderboard function below.
function climbingLeaderboard(scores, alice) {
const ans = [];
let count = 0;
// the alice array is arranged in ascending order
let j = alice.length - 1;
for (let i = 0 ; i < scores.length ; i++) {
const score = scores[i];
for (; j >= 0 ; j--) {
if (alice[j] >= score) {
// if higher than score
ans.unshift(count+1);
} else if (i === scores.length - 1) {
// if smallest
ans.unshift(count+2);
} else {
break;
}
}
// actual rank of the score in leaderboard
if (score !== scores[i-1]) {
count++;
}
}
return ans;
}
Here is my solution
List<int> distinct = null;
List<int> rank = new List<int>();
foreach (int item in player)
{
ranked.Add(item);
ranked.Sort();
ranked.Reverse();
distinct = ranked.Distinct().ToList();
for (int i = 0; i < distinct.Count; i++)
{
if (item == distinct[i])
{
rank.Add(i + 1);
break;
}
}
}
return rank;
This can be modified by removing the inner for loop also
List<int> distinct = null;
List<int> rank = new List<int>();
foreach (int item in player)
{
ranked.Add(item);
ranked.Sort();
ranked.Reverse();
distinct = ranked.Distinct().ToList();
var index = ranked.FindIndex(x => x == item);
rank.Add(index + 1);
}
return rank;
This is my solution in c# for Hackerrank Climbing the Leaderboard based on C++ answer here.
public static List<int> climbingLeaderboard(List<int> ranked, List<int> player)
{
List<int> _ranked = new List<int>();
_ranked.Add(ranked[0]);
for(int a=1; a < ranked.Count(); a++)
if(_ranked[_ranked.Count()-1] != ranked[a])
_ranked.Add(ranked[a]);
int j = _ranked.Count()-1;
int i = 0;
while(i < player.Count())
{
if(j < 0)
{
player[i] = 1;
i++;
continue;
}
if(player[i] < _ranked[j])
{
player[i] = j+2;
i++;
}
else
if(player[i] == _ranked[j])
{
player[i] = j+1;
i++;
}
else
{
j--;
}
}
return player;
}
My solution in Java for climbing the Leaderboard Hackerrank problem.
// Complete the climbingLeaderboard function below.
static int[] climbingLeaderboard(int[] scores, int[] alice) {
Arrays.sort(scores);
HashSet<Integer> set = new HashSet<Integer>();
int[] ar = new int[alice.length];
int sc = 0;
for(int i=0; i<alice.length; i++){
sc = 1;
set.clear();
for(int j=0; j<scores.length; j++){
if(alice[i] < scores[j] && !set.contains(scores[j])){
sc++;
set.add(scores[j]);
}
}
ar[i] = sc;
}return ar;
}

How do we count the number of occurrence from left to right and continue until we have consecutive numbers?

So the code that I wrote, is for the number of occurrence. Suppose in the sample part which is mentioned, if I give an input Array of {2,1,1,1,3}, it will give me the count of Number 2 occurrence as 1. Now, I'm struggling to write the code in a manner so that it gives me the count only if it's continuous from left to right. Suppose, if my array is {1,1,1,2,0}, only then it will give me the total occurrence of 1 as 3, but not if it's {1,0,1,2,1} or {0,0,1,1,1} or {1,1,2,2,1}
static void Evaluate_V5B(int[] window, int[] PayCombos,)
{
int[] Counters1 = new int[3];
for (int index0 = 0; index0 < 5; index0++)
{
Console.Write("{0} ", window[index0]);
int symbol = window[index0];
Counters1[symbol]++;
}
Console.WriteLine();
for (int indexJ = 0; indexJ < Counters1.Length; indexJ++)
{
Console.WriteLine("{0}", Counters1[indexJ]);
}
}
This will take the 1st element in the array and return continuous occurrences from left to right. If that element found anywhere else it will return 0 as count:
static void Evaluate(int[] array)
{
var count = 1;
var first = array[0];
for (int i = 1; i < array.Length; i++)
{
if(array[i] == first)
{
count++;
}
else{
for (int j = i + 1; j < array.Length; j++)
{
if(first == array[j]) {
count = 0;
break;
}
}
break;
}
}
Console.WriteLine($"Count of Number {first} occurrence is {count}");
}
This function will find the number of continuous occurrences of a specific number num in the array nums, if it is the first number.
static int ContinuousOccurrences(int[] nums, int num)
{
if (nums[0] == num)
{
int continuousOccurrences =
nums.TakeWhile(x => x == num).Count();
int totalOccurrences =
nums.Where(x => x == num).Count();
if(continuousOccurrences == totalOccurrences)
{
return continuousOccurrences;
}
else
{
return 0;
}
}
return 0;
}
If you want to know the number of continuous occurrences of the first number, call the function this way:
ContinuousOccurrences(nums, nums[0])

Trouble creating algorithm that modifies elements of a 2d array

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();
}
}

why is the output in lottery code isn't working?

I'm supposed to make a code in c# (microsoft visual studio 2017) that lets the user input six numbers, and then compare them to an array of six randomly generated numbers(with no duplicates).
If the user has one match, he's supposed to get a message saying he had one match, and different messages for two or three matches, and so on.
This is what I got so far:
static bool isValueInArray(int value, int[] a)
{
for (int i = 0; i < a.Length; i++)
{
if (a[i] == value)
{
return true;
}
}
return false;
}
static void Main(string[] args)
{
int min = 0;
int max = 6;
Random randnum = new Random();//random number generator
int[] numbers = new int[6];// generates six numbers
for (int i = 0; i < numbers.Length; i++)
{
numbers[i] = randnum.Next(min, max);//sets the numbers between 0 to 6
if(isValueInArray( i, numbers))
{
numbers[i] = randnum.Next(min, max);
}
}
try
{
Console.WriteLine("Hello and Welcome to our little game of lottery! lets see just how much luck you got!"); // greetings and instructions
Console.WriteLine("You'll now get to choose 6 different numbers between 0 to 6 to play with.");
Console.WriteLine("Go ahead and type them in.");
int[] lottery = new int[6];
for (int i = 0; i < lottery.Length; i++)
{
lottery[i] = int.Parse(Console.ReadLine()); // array to catch six numbers input
if (lottery[i] > 6)//checking if the numbers fit between 0 and 6
{
Console.WriteLine("whoops! the number you enetered isn't in range! please try again ^^");
break;
}
int x = 6;
for (int a = 0; a < lottery.Length; a++)
{
for (int b = 0; b < numbers.Length; b++)
{
if (lottery[a] == numbers[b])
{
a++;
x--;
if (x == 6)
{
Console.WriteLine("six match");
break;
}
else if (x == 5)
{
Console.WriteLine("five match");
break;
}
else if (x == 4)
{
Console.WriteLine("four match");
break;
}
else if (x == 3)
{
Console.WriteLine("three match");
break;
}
else if (x == 2)
{
Console.WriteLine("two match");
break;
}
else if (x == 1)
{
Console.WriteLine("one match");
break;
}
}
}
}
}
}
catch (FormatException)// checking if the input is in char format
{
Console.WriteLine("only numbers please!");
}
}
My problem is with the output. The program seems to go over all of the "else if" options and print all of them, instead of picking and printing just one of them.
You have everything mixed together. Write out the steps:
Generate numbers
Get input from user
Count number of matches
Print results
Each step should be performed separately.
// These should be the min/max lottery numbers
int min = 1;
int max = 100;
int numberOfLotteryNumbers = 6;
// Renamed for clarity
int[] lotteryNumbers = new int[numberOfLotteryNumbers];
int[] userNumbers = new int[numberOfLotteryNumbers];
// Step 1 - generate numbers
for (int i = 0; i < lotteryNumbers.Length; i++) {
int randomNumber;
do {
randomNumber = randnum.Next(min, max);
} while (isValueInArray(randomNumber, lotteryNumbers));
lotteryNumbers[i] = randomNumber;
}
// Step 2 - get numbers from user
for (int i = 0; i < lottery.Length; i++) {
int userInput;
do {
userInput = int.Parse(Console.ReadLine());
} while (userInput < min || userInput > max || isValueInArray(userInput, userNumbers));
userNumbers[i] = userInput;
}
// Step 3 - calc matches
int matches = 0;
for (int i = 0; i < userNumbers.Length; i++) {
if (isValueInArray(userNumbers[i], lotteryNumbers) {
matches += 1;
}
}
// Step 4 - print results
Console.WriteLine("There are {0} matches.", matches);
You may have to rearrange the code blocks in a way to get user input first, calculate the number of matches first, then display results as following code:
Note: Your approach to guarantee unique numbers in the randomly generated number ain't going to work as you expect to, you are passing "i" where you may want to pass "numbers[i]" instead to the isValueInArray" function. Let aside the idea that you will always end with values 0-5 in the array since you want 6 numbers.
int min = 0;
int max = 6;
Random randnum = new Random();//random number generator
int[] numbers = new int[6];// generates six numbers
for (int i = 0; i < numbers.Length; i++)
{
numbers[i] = randnum.Next(min, max);//sets the numbers between 0 to 6
if (isValueInArray(i, numbers))
{
numbers[i] = randnum.Next(min, max);
}
}
try
{
Console.WriteLine("Hello and Welcome to our little game of lottery! lets see just how much luck you got!"); // greetings and instructions
Console.WriteLine("You'll now get to choose 6 different numbers between 0 to 6 to play with.");
Console.WriteLine("Go ahead and type them in.");
int[] lottery = new int[6];
int x = 0;
//read user numbers
for (int i = 0; i < lottery.Length; i++)
{
lottery[i] = int.Parse(Console.ReadLine()); // array to catch six numbers input
while (lottery[i] > 6)//checking if the numbers fit between 0 and 6
{
Console.WriteLine("whoops! the number you enetered isn't in range! please try again ^^");
lottery[i] = int.Parse(Console.ReadLine()); // array to catch six numbers input
}
}
//count number of matches
for (int a = 0; a < lottery.Length; a++)
{
for (int b = 0; b < numbers.Length; b++)
{
if (lottery[a] == numbers[b])
{
//a++;
x++;
break;
}
}
}
//display results
if (x == 6)
{
Console.WriteLine("six matches");
}
else if (x == 5)
{
Console.WriteLine("five matches");
}
else if (x == 4)
{
Console.WriteLine("four matches");
}
else if (x == 3)
{
Console.WriteLine("three matches");
}
else if (x == 2)
{
Console.WriteLine("two matches");
}
else if (x == 1)
{
Console.WriteLine("one match");
}
}
catch (FormatException)// checking if the input is in char format
{
Console.WriteLine("only numbers please!");
}
Console.Read();
}
You can use a counter to achieve your goal. Just increment counter value on match:
int counter = 0;
for (int i = 0; i < lottery.Length; i++)
{
// ..
if (x == number)
{
counter++;
break;
}
// ..
}
Console.WriteLine("You have " + counter + " matches");

Categories

Resources