Printing a sorted array - c#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace SkihopperOpgave
{
class Program
{
static void Main(string[] args)
{
string deltagerNavn = " ";
int hopLængde = 0;
string[] deltager = new string[5];
int[] hopLængder = new int[5];
string[] pladsNumre = new string[5] { "1. ", "2. ", "3. ", "4. ", "5. " };
for (int i = 0; i < deltager.Length; i++)
{
Console.Write("Indtast deltagernavn: ");
deltager[i] = Console.ReadLine();
Console.Write("Indtast hoplængde for deltager: ");
hopLængder[i] = Convert.ToInt32(Console.ReadLine());
for (int j = hopLængder.Length-1; j>0; j--) //Bubblesort
{
for (int k = 0; k < j; k++)
{
int b = hopLængder[k];
hopLængder[k] = hopLængder[k+1];
hopLængder[k+1] = b;
}
}
for (int s = 0; s < deltager.Length; s++)
{
Console.WriteLine(pladsNumre[s] + hopLængder[s] + deltager[s]);
}
}
}
}
}
I am trying to create a program that prints out a sorted list of Ski jumpers (deltagere), by sorting their jump distance (hoplængde). What happens is that the user first types in the name of the ski jumper, then the jump distance. The program should then print out a sorted list in this format: 1. 80 John (Newline) 2. 45 Mark... etc.
Each time a user types in a ski jumper, the list should be printed, with all the distances sorted in a descending order.
I've created an array for both names of the ski jumpers and their distances, but I am having trouble as to how I connect the first element in the int array with the first element in the string array and how to correctly sort this in each iteration.
I tried creating a bubblesort for the job, but I get wrong results.

Take a look at overloads of static method Array.Sort() - it can do what you want.
Also you should read about SortedList<> class - it is probably even better option for your task and use comments already posted (by Fischerman) to declare an entity class.
I think that's enough hints for a homework =)

Related

How do I sort a random list of 7 numbers out of 35? [duplicate]

This question already has answers here:
Sorting a List<int>
(7 answers)
Closed 1 year ago.
I want to create a lotto-game and randomly pick 7 different numbers out of 35 numbers in C#. That is what I do in the code but I do not understand how to sort the numbers in ascending order. What I do is to pick out 7 numbers from a list that has 35 numbers and now I am so confused so I need help that at least put me in another way of thinking.lf someone could hlep me with this I would be very glad. I realize that I have messed it up some with the naming. That is (for instance) I create a list (winningNumber) that contains all but the 7 random numbers I want to sort but right now I need help to sort my messy thoughts out.
Here is the code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Random_Lotto_Number_2021_05_28_SMART
{
class Program
{
static void Main(string[] args)
{
Random rndLottoNumber = new Random();
List<int> winningNumber = new List<int>();
for (int i = 1; i <= 35; i++)
winningNumber.Add(i);
for (int i = 0; i < 7; i++)
{
int drawnNumber = rndLottoNumber.Next(winningNumber.Count);
//Console.ReadLine();
Console.Write(winningNumber[drawnNumber] + ",");
winningNumber.RemoveAt(drawnNumber);
}
Console.WriteLine($"\nThe list contains {winningNumber.Count}");
foreach(int num in winningNumber)
{
Console.Write(num + ",");
}
Console.ReadLine();
}
}
}
You could simply add your "lucky" drawn numbers to a new list, and then sort that list, as shown below:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
public class Program
{
public static void Main()
{
Random rndLottoNumber = new Random();
List<int> winningNumber = new List<int>();
List<int> drawnNumberList = new List<int>();
for (int i = 1; i <= 35; i++)
winningNumber.Add(i);
for (int i = 0; i < 7; i++)
{
int drawnNumber = rndLottoNumber.Next(winningNumber.Count);
// Add numbers to list
drawnNumberList.Add(winningNumber[drawnNumber]);
//Console.ReadLine();
Console.Write(winningNumber[drawnNumber] + ",");
winningNumber.RemoveAt(drawnNumber);
}
Console.Write("\nThe list contains ");
Console.WriteLine(winningNumber.Count);
foreach(int num in winningNumber)
{
Console.Write(num + ",");
}
Console.WriteLine();
// Sort the list
drawnNumberList.Sort();
foreach(int num in drawnNumberList)
{
Console.Write(num + ",");
}
}
}
A way to assist with these problems is to write down what you are trying to do on a piece of old-fashioned paper writing either a flowchart or pseudo-code. I have used this countless times when trying to order my thoughts around a programming problem.

Different program outputs when different capacity arguments are passed to List constructor, C#

I'm implementing a slightly fancier version of counting sort in C#. The "slightly fancier" part is that I replace some elements in the sorted output with "-" rather than the original value. Here is a sample input/ output pair (the range of possible integer values are between 0 and 99):
IN
20
0 ab
6 cd
0 ef
6 gh
4 ij
0 ab
6 cd
0 ef
6 gh
0 ij
4 that
3 be
0 to
1 be
5 question
1 or
2 not
4 is
2 to
4 the
OUT
- - - - - to be or not to be - that is the question - - - -
And here is my implementation:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
class Solution
{
static void Main(String[] args)
{
int n = Convert.ToInt32(Console.ReadLine());
List<List<string>> rsltLists = new List<List<string>>(100);
for(int i=0; i<n; i++)
{
rsltLists.Add(new List<String>()); // PROBLEM IS HERE
}
for(int a0 = 0; a0 < n; a0++)
{
string[] tokens_x = Console.ReadLine().Split(' ');
int x = Convert.ToInt32(tokens_x[0]);
string s = tokens_x[1];
if(a0 < n/2)
{
// Replace string with '-'
rsltLists[x].Add("-");
}
else
{
rsltLists[x].Add(s);
}
}
foreach(List<string> rsltList in rsltLists)
{
foreach(string rslt in rsltList)
{
Console.Write(rslt + " ");
}
}
}
}
I'm submitting my code as the solution to a problem on Hackerrank. The problem is that for the 5th test case, my solution times out (the test case contains an enormous number of lines so I'm not including it here). To speed my solution up, I replaced the //PROBLEM IS HERE line with rsltLists.Add(new List<String>(100)). This causes the 5th test case to fail rather than time out (test cases 1-4 still passed). When I replaced the problem line with rsltLists.Add(new List<String>(10000)) the 5th test case and several other test cases failed (though not all of the test cases failed). Why would changing the amount of space I reserve for each List<String> cause this inconsistent behavior? I would expected the fifth test case to fail (maybe), but I wouldn't have expected test cases that were passing previously to start failing.
Why are you creating n rsltLists? That is not the requirement. There are 100 possible values and array is better for that. You should NOT be using n here. x is 100.
for(int i=0; i<n; i++) // no, problem is here
{
rsltLists.Add(new List<String>()); // PROBLEM IS HERE
}
This should be pretty fast
public static string HackerSort()
{
List<string> input = new List<string>() {"20"
, "0 ab"
, "6 cd"
, "0 ef"
, "6 gh"
, "4 ij"
, "0 ab"
, "6 cd"
, "0 ef"
, "6 gh"
, "0 ij"
, "4 that"
, "3 be"
, "0 to"
, "1 be"
, "5 question"
, "1 or"
, "2 not"
, "4 is"
, "2 to"
, "4 the" };
List<string>[] wl = new List<string>[100];
int n = int.Parse(input[0]);
int half = n/2;
char split = ' ';
for (int i = 0; i < n; i++)
{
string s = input[i + 1];
string[] ss = s.Split(split);
//Debug.WriteLine(ss[0]);
int row = int.Parse(ss[0]);
if(wl[row] == null)
{
wl[row] = new List<string>((n / 100) + 1);
}
wl[row].Add(i < half ? "-" : ss[1]);
}
StringBuilder sb = new StringBuilder();
foreach(List<string> ls in wl.Where(x => x != null))
{
sb.Append(string.Join(" ", ls) + ' ');
}
Debug.WriteLine(sb.ToString().TrimEnd());
return sb.ToString().TrimEnd();
}
Couple thoughts on this:
You're creating a list for each option... but many aren't used. How about only instantiating the lists that you'll actually use?
Compounded with the one above, you're creating 100 lists, each with a capacity of 100... that's a lot of memory to set aside that you won't be using
One solution:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
class Solution
{
static void Main(String[] args)
{
int n = Convert.ToInt32(Console.ReadLine());
int threshold = n / 2;
List<string>[] stringMap = new List<string>[100];
for(int a0 = 0; a0 < n; a0++){
string[] tokens_x = Console.ReadLine().Split(' ');
int x = Convert.ToInt32(tokens_x[0]);
if(stringMap[x] == null)
{
stringMap[x] = new List<string>();
}
stringMap[x].Add((a0 >= threshold ? tokens_x[1] : "-"));
}
List<string> output = new List<string>();
for(int i = 0; i < stringMap.Length; i++)
{
if(stringMap[i] == null)
{
continue;
}
output.AddRange(stringMap[i]);
}
Console.WriteLine(string.Join(" ", output));
}
}
The "inner" List will always have exactly two elements, one of which you want to treat as a number rather than a string. Better to use a small class or even a tuple here, rather than nested lists.
I'm at work with only VS2015 with no tuple support, so this code is unchecked and likely has a mistake or two:
static void Main(String[] args)
{
int n = int.Parse(Console.ReadLine());
var data = new List<(int, string)>(n);
for(int a0 = 0; a0 < n; a0++)
{
var tokens = Console.ReadLine().Split(' ');
int x = int.Parse(tokens[0]);
if(a0 < n/2) tokens[1] = "-";
data.Add( (val: x, str: tokens[1]) )
}
foreach(var item in data.OrderBy(i => i.val))
{
Console.Write(item.str + " ");
}
}
One way to solve the memory-hogging / long processing times would be to store the input in a SortedDictionary<int, List<string>> instead. The Key would be the integer portion of the input, and the Value would be a List<string> containing the other part of the input (one item per input that matches the key).
Then, when we have the dictionary populated, we can just output each List<string> of data in order (the SortedDictionary will already be sorted by Key).
In this way, we're only creating as many lists as we actually need, and each list is only as long as it needs to be (both of which I believe were causes for the errors in your original code, but I don't know where to find the actual test case code to verify).
private static void Main()
{
var length = Convert.ToInt32(Console.ReadLine());
var halfway = length / 2;
var items = new SortedDictionary<int, List<string>>();
for (int inputLine = 0; inputLine < length; inputLine++)
{
var input = Console.ReadLine().Split();
var sortIndex = Convert.ToInt32(input[0]);
var value = inputLine < halfway ? "-" : input[1];
if (items.ContainsKey(sortIndex)
{
items[sortIndex].Add(value);
}
else
{
items.Add(sortIndex, new List<string> {value});
}
}
Console.WriteLine(string.Join(" ", items.SelectMany(i => i.Value)));
// Not submitted to website, but for local testing:
Console.Write("\n\nPress any key to exit...");
Console.ReadKey();
}
Output

C# user input to set size of array and loop array to display elements

The goal is to create an array size from user input via how many test scores. Then create a loop that will populate an array by prompting the user for each test score from 0 to 100.
Finally display the results, typically using another loop.
Question: Why is it when the test scores are entered example "50" it adds 50 elements of 0 to the array?
any assistance would be grateful, thank you. I've seen a few similar posts but couldn't resolve this issue. Also, one was in Spanish.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;
namespace ConsoleApp3
{
class Program
{
static void Main(string[] args)
{
// prompt user to ask how many test scores to build the size of the array
Write("How many test scores total: ");
string sSize = ReadLine();
int i = Convert.ToInt32(sSize);
int[] score = new int[i];
// create the loop of asking the test scores limited to the array sSize
for (int a = 1; a < i + 1; a++)
{
Write("Please enter a test score " + a + " from 0 to 100: ");
string testArray = ReadLine();
int g = Convert.ToInt32(testArray);
int[] tests = new int[g];
//create loop to display all test scores
foreach (var item in tests)
Console.WriteLine(item);
}
}
}
}
int[] tests = new int[g];
Here you are assigning the size of the array given by the user rather than populating the array, you are missing the populating statement or query for that.
Because you create a new array inside of your loop that is the size of the "score" the user entered and then you loop over it. The values are all zero because when you create an array it is populated with the default value of the type, in this case 0. The second loop should be after the first one and you shouldn't be creating arrays inside of the first loop, just populating the original array (score) that you created to begin with.
Here's what you actually want. Note that you should index starting at 0 and not 1.
Write("How many test scores total: ");
string sSize = ReadLine();
int i = Convert.ToInt32(sSize);
int[] score = new int[i];
// create the loop of asking the test scores limited to the array sSize
for (int a = 0; a < i; a++)
{
Write("Please enter a test score " + (a + 1) + " from 0 to 100: ");
string testArray = ReadLine();
int g = Convert.ToInt32(testArray);
score[a] = g;
}
//create loop to display all test scores
foreach (var item in score)
Console.WriteLine(item);
You may also want to consider using int.TryParse so you can determine if the user enters an invalid value.
I think you copied pieces of code from different places and haven't been able to put them together properly.
You are creating an unwanted array here : int[] tests = new int[g];. And then trying to use it just worsens your situation.
Also, you haven't handled your indexes properly. When you are learning to program, using proper formatting and good variable names, will help you understand your own code (potentially put together from different places) a lot better - improving your "debugging" skills.
I have a "fixed" version of your code which should be self-explanatory
using System;
using static System.Console;
namespace ConsoleApp3 {
class Program {
static void Main(string[] args) {
// prompt user to ask how many test scores to build the size of the array
Write("How many test scores total: ");
string testCountStr = ReadLine();
int testCount = Convert.ToInt32(testCountStr );
int[] testScores = new int[testCount];
// create the loop of asking the test scores limited to the array sSize
for (int i = 0; i < testCount; i++) {
Write($"Please enter score for test {i + 1} from 0 to 100: ");
string scoreStr = ReadLine();
int score = Convert.ToInt32(scoreStr);
if (score > 100 || score < 0) {
//TODO: handle your error
WriteLine("Invalid score. Please try again");
--i;
continue;
}
testScores[i] = score;
}
WriteLine();
// create loop to display all test scores
for (int i = 0; i < testScores.Length; ++i)
WriteLine($"Your score for test {i + 1} is {testScores[i]}");
}
}
}

Issue with bucket sort for strings C#

I am writing a program that takes in data for student info with a student ID # field, student first name field and student last name field. The user will input the data for each student (up to 20 students) or until the user enters '999' for the student ID field. Next I would like to sort the student info into two separate buckets based on the last name field.
I am having an issue with the buckets separating correctly. I will use the CompareTo method to compare the last name strings for the student last name array but when I print the buckets they are mixed up. For example, the last names starting with A-K should go into a 'low values' bucket and last names starting with J-Z should go into a 'high values' bucket.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace _123_Assignment2
{
using System;
using static System.Console;
class Program
{
struct student
{
public int studentId;
public string firstName;
public string lastName;
};
static void Main(string[] args)
{
student[] studentInfo = new student[20];
string[] bucketLow = new string[20];
string[] bucketHigh = new string [20];
int x = 0;
int y = 0;
int z = 1;
WriteLine("Enter student ID number:");
studentInfo[x].studentId = Convert.ToInt32(ReadLine());
while (studentInfo[x].studentId != 999)
{
WriteLine("Enter first name:");
studentInfo[x].firstName = ReadLine();
WriteLine("Enter last name:");
studentInfo[x].lastName = ReadLine();
x++;
WriteLine("Enter student ID number:");
studentInfo[x].studentId = Convert.ToInt32(ReadLine());
}
for (int j = 0; j < x; j++)
{
if(studentInfo[j].lastName.CompareTo(studentInfo[z].lastName)<= 0)
bucketLow[y] = studentInfo[j].lastName;
else
bucketHigh[y] = studentInfo[j].lastName;
y++;
z++;
}
WriteLine("Unsorted Table:");
for (int j = 0; j < studentInfo.Length; j++)
{
WriteLine("{0}{1}{2}",studentInfo[j].studentId,studentInfo[j].firstName,
studentInfo[j].lastName);
}
WriteLine("Bucket 1:");
for (int j = 0; j < x; j++)
{
WriteLine(bucketLow[j]);
}
WriteLine("Bucket 2:");
for (int j = 0; j < x; j++)
{
WriteLine(bucketHigh[j]);
}
}
}
}
I believe I am not writing the CompareTo method correctly, I tried sorting from both the beginning and end of the array respectively and keep getting the same results?
As this appears to be homework, I'll refrain from actually writing the correct code for you. But here are at least some of your problems:
Directly addressing your concern, the code you have to sort the array elements is using the wrong comparison. If you have two buckets, and you want one to represent last names starting with A through K and the other to represent last names starting with L through Z, then you need to compare to K or L to determine the right bucket. Comparing to other names is just going to randomize the data. Something like string.Compare(studentInfo[j].lastName, "L", StringComparison.CurrentCultureIgnoreCase) < 0 should work.
You need to maintain two indexes, one for each bucket, and only increment an index for that bucket if you've actually copied a student record to that bucket.
Your current code will crash with an IndexOutOfRangeException if you actually try to entry data for 20 students, because you increment x and store the ID value into the array without checking to see if you've entered 20 student's worth of data yet. After 20 students have been entered, then even if the user enters 999, the while condition won't check that until it's too late and the code has already tried to stored the value into the array.
There may be other problems; those are the ones that I noticed at first glance.
For future reference, you should make sure when asking questions here on Stack Overflow that you provide a good Minimal, Complete, and Verifiable code example. You came close; at least the code was complete. But don't make other SO users enter your test data. Write a separate program that includes all the data built-in, doesn't have user prompts, and doesn't do anything that isn't strictly required to reproduce the issue you're having.
I do not think that you sorting works (the j and z comparisons):
studentInfo[j].lastName.CompareTo(studentInfo[z].lastName)<= 0
Try to simplify your bucket sort - if you know that your buckets are A-K and J-Z maybe you should replace the part of:
for (int j = 0; j < x; j++)
{
if(studentInfo[j].lastName.CompareTo(studentInfo[z].lastName)<= 0)
bucketLow[y] = studentInfo[j].lastName;
else
bucketHigh[y] = studentInfo[j].lastName;
y++;
z++;
}
}
Try something like:
for (var i = 0; i < studentInfo.Length; i++)
{
if (studentInfo[i].lastName[0] <= 'K')
bucketLow[y] = studentInfo[i].lastName;
else
bucketHigh[y] = studentInfo[i].lastName;
y++;
}
(And of course add some check that you have a valid input of at least 1 character and so on...)
If you must use a struct and arrays then you may consider the code below for separating the names into the appropriate buckets. As I commented you need to two indexes, one for each bucket. Because you are fixing the array sizes to 20, there will be empty rows when outputting the results if there are less than 20.
x = studentInfo.Length;
int lowIndex = 0;
int highIndex = 0;
for (int j = 0; j < x; j++) {
if (String.CompareOrdinal(studentInfo[j].lastName, "L") < 0) {
bucketLow[lowIndex] = studentInfo[j].lastName;
lowIndex++;
} else {
bucketHigh[highIndex] = studentInfo[j].lastName;
highIndex++;
}
}

Read array of integers from user which is separated by space in C#

I was asked to solve a problem in C# to get the sum of 'n' user inputs from console, which is separated by space, in a single line.
int n = Convert.ToInt32(Console.ReadLine());
int[] arr = new int[n];
int sum = 0;
for(int i = 0; i < n; i++) {
arr[i] = Convert.ToInt32(Console.ReadLine());
sum += arr[i];
}
Console.WriteLine("{0}",sum);
How can I modify this code to get the expected output from the space separated input?
Also the values need to be stored in array.
Input:
5
1 2 3 4 5
Output:
15
int result = Console.ReadLine().Split().Select(int.Parse).Sum();
You'll of course have to handle any bad user input as needed.
Per your added requirements:
int[] items = Console.ReadLine().Split().Select(int.Parse).ToArray();
int sum = items.Sum();
You could do something like this:
int result = input.Split(' ').Take(n).Select(int.Parse).Sum();
But it seems to me that you could avoid asking the user for the count, and just add together all the lines that they typed in:
string input = Console.ReadLine();
int result = input.Split(' ').Select(int.Parse).Sum();
Console.WriteLine(result);
(Note that this code does no error checking.)
EDIT: It seems that you want to have an array of ints. In that case, you can do it like this (again, with no error checking):
using System;
using System.Linq;
namespace Demo
{
internal class Program
{
private static void Main()
{
int n = int.Parse(Console.ReadLine());
int[] arr = Console.ReadLine().Split(' ').Take(n).Select(int.Parse).ToArray();
int sum = arr.Sum();
Console.WriteLine("{0}", sum);
}
}
}
You need to use the split function in C#. When you read the line, you get the whole line. This means you're attempting to say "sum = 0 plus Convert.ToInt32('5 1 2 3 4 5')" which doesn't work.
You need an array of integers equal to
Console.ReadLine().Split(" ");
String.Split function:
https://msdn.microsoft.com/en-us/library/b873y76a.aspx
using arr[i] = Convert.ToInt32(Console.ReadLine()) inside the loop will cause the program to expect an input on a different line and not on a single line.
What you can do is to take the input as a string and then split based on space, which produces an array of the inputed values. You can then sum them
Considering the fact that Naveen seems a student, I think some more code can explain better and let him learn some more from this exercise:
I've made a sample that gets some numbers separated by space or an enter and when the user enters a T calculates the sum in a traditional way using a loop and using Linq. I'm sure there are plenty of better ways to do the same, but maybe something a little bit more structured can be better to begin understanding C#.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SumTheNumbers
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Insert the numbers separated by a space or [Enter]> key, when finished write T and press [Enter] and you will have the result");
List<int> values = new List<int>();
while (true)
{
string inputData = Console.ReadLine();
if (inputData.ToUpper().StartsWith("T")) break;
string[] svals = inputData.Split(' ');
for (int i = 0; i < svals.Length; i++)
{
int x = 0;
int.TryParse(svals[i], out x);
if (x != 0) values.Add(x);
}
}
//Traditional mode
int total = 0;
for (int i = 0; i < values.Count; i++)
{
total = total + values[i];
}
//Linq mode
int totalLinq = values.Sum();
Console.WriteLine("The sum is");
Console.Write("Total: ");
Console.WriteLine(total.ToString());
Console.Write("Total linq: ");
Console.WriteLine(totalLinq.ToString());
Console.WriteLine("Press a key to end...");
Console.ReadKey();
}
}
}

Categories