Concat error in C# - c#

I have a quick sort program using lists.
The error is in the quick sort function return statement.
System.Collections.List does not contain definition for Concat and the best extension method System.Collections.Generic.IEnumerableTsource has some invalid arguments.
The code is as follows.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Enter the n9o. of elements: ");
int n = Convert.ToInt32(Console.ReadLine());
List<int> unsorted = new List<int>();
Console.WriteLine("Enter the elements: ");
for (int i = 0; i < n; i++)
{
unsorted.Add(Convert.ToInt32(Console.ReadLine()));
}
List<int> sorted = quicksort(unsorted);
foreach (int entry in sorted)
{
Console.Write(entry + "\t");
}
return;
} //end of main.
public static List<int> quicksort(List<int> given)
{
if (given.Count == 1)
return given;
int mid = given.Count / 2;
List<int> less = new List<int>();
List<int> big = new List<int>();
for (int a = 0; a < given.Count; a++)
{
if (given[a] < mid)
{
less.Add(given[a]);
}
else
big.Add(given[a]);
}
return (quicksort(less).Concat(given[mid]).Concat(quicksort(big)));
}
}//end of class.
}//end of namespace.

You can't Concat an int into an IEnumerable<int>. You could instead wrap it in an array and Concat that to your other lists:
return quicksort(less)
.Concat(new[] { given[mid] })
.Concat(quicksort(big))
.ToList();

As the error is trying to tell you, the Concat() method takes a collection of items to concatenate, not a single int.

I think adding given[mid] to the resulting list is a mistake, since it will add the item to your resulting list twice...
also, you need to test against given[mid] not mid
So you should change your if statement to:
if (given[a] < given[mid])
less.Add(given[a]);
else if (given[a] > given[mid])
big.Add(given[a]);
This is assuming that all numbers are unique as well, because if given[mid] is not unique, then you have a problem

Related

Better way to do this ( using LINQ )?

I am comparing two lists and in one case I am removing the uncommon elements from one list ( removing from lists with more number of elements ) and in the other case (else statement) I am adding the uncommon elements to one list ( adding to list with lesser elements )
I am able to do this using the below given code but I was hoping to achieve this using LINQ in a more concise manner. Please suggest me an equivalent LINQ code
if (receivedList.Count < AuthorFacets.Count)
{
for (int i = AuthorFacets.Count - 1; i >= 0; i--)
{
if (!receivedList.Contains(AuthorFacets[i]))
AuthorFacets.RemoveAt(i);
}
}
else
{
for (int i = 0; i < receivedList.Count; i++)
{
if (!AuthorFacets.Contains(receivedList[i]))
AuthorFacets.Add(receivedList[i]);
}
}
Using linq you can try this
if (receivedList.Count < AuthorFacets.Count)
{
AuthorFacets.RemoveAll(a=>!receivedList.Contains(a))
}
else
{
AuthorFactets.AddRange(receivedList.Where(r=> !AuthorFacets.Contains(r)))
}
How about this?
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
var receivedList = new List<string>();
var AuthorFacets = new List<string>();
receivedList.Add("2");
receivedList.Add("4");
receivedList.Add("6");
AuthorFacets.Add("1");
AuthorFacets.Add("2");
AuthorFacets.Add("3");
if (receivedList.Count < AuthorFacets.Count)
{
AuthorFacets = AuthorFacets.Where(i => receivedList.Contains(i)).ToList();
}
else
{
AuthorFacets.AddRange(receivedList.Where(i => !AuthorFacets.Contains(i)));
}
Console.WriteLine(string.Join("\n",AuthorFacets));
}
}
Source Code: https://dotnetfiddle.net/Hz8anK

How do I split an array into two different arrays?

I can't seem to figure out how to fix my code so that it works. I need the user to be able to input their first name then space then the what they scored. Then I need to split the array into two different arrays and pass them to the four different methods to display to the user what they scored, etc. Can anyone help me figure this problem out?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace proj09LEA
{
class Program
{
static void Main(string[] args)
{
// declare and array of integers
int[] array = new int[10];
Console.WriteLine("\nSaturday Coder's Bowling Team");
Console.WriteLine("Enter in a name and score for each person on the team.");
Console.WriteLine("For example, Mary 143. Just hit Enter when you are done.\n");
// fill an array with user input
for (int i = 0; i < array.Length; i++)
{
Console.WriteLine("Enter in a name and score: ");
string userInput;
string[] parsedInput;
parsedInput = userInput.Split();
string name = parsedInput[0];
int score = int.Parse(parsedInput[1]);
}
Console.WriteLine("------------ Input Complete ------------\n");
Console.WriteLine("Here are the scores for this game:");
DisplayScore(array);
HighScore(array);
LowScore(array);
AverageScore(array);
Console.WriteLine("Press Enter to continue. . .");
Console.ReadLine();
}
static void DisplayScore(int[] array)
{
foreach (int n in array)
{
Console.WriteLine("{0}'s score was {0}.\n", array);
}
}
static void HighScore(int[] array)
{
int max = array.Max();
Console.WriteLine("Congratulations {0}, your score of {0} was the highest.", max);
}
static void LowScore(int[] array)
{
int min = array.Min();
Console.WriteLine("{0}, your score of {0} was the lowest. Better get some practice.", min);
}
static void AverageScore(int[] array)
{
int sum = array.Sum();
int average = sum / array.Length;
Console.WriteLine("The average score for this game was {0:d}.", average);
}
}
}
If you absolutely have to use simple primitive arrays, you would need two distinct arrays of the same size, to hold the names as strings and scores as ints:
class Program
{
const int MaxScores = 10; // .. Use a constant to ensure the sizes remain in sync
static void Main(string[] args)
{ ///
string[] names = new int[MaxScores];
int[] scores = new int[MaxScores];
// ... parse names into names[] and scores into scores[]
DisplayScore(names, scores);
You would then need to pass both arrays to the various methods:
static void DisplayScore(string[] names, int[] scores)
{
for(int i=0; i < MaxScores; i++)
{
Console.WriteLine("{0}'s score was {1}.\n", names[i], scores[i]);
}
}
// etc
However, there are better ways to do this, e.g. by defining a custom class for the tuple of Name, Score:
class PersonScore
{
public string Name {get; set;}
public int Score {get; set;}
}
You can then declare and pass the single array of PersonScore[] around.
PersonScore[] personScores = new PersonScore[MaxScores];
for (... prompting the user for data)
{
... parsing user input
personScores[i] = new PersonScore{Name = name, Score = score};
}
DisplayScore(personScores); // Pass around the single array
static void DisplayScore(IEnumerable personScores)
{
foreach(var personScore in personScores)
{
Console.WriteLine("{0}'s score was {1}.\n", personScore.Name, personScores.Score);
}
}
// etc - other methods
As others have mentioned, other collections are also possible alternatives to an array, most commonly List.
You can do like this. Just use Console.ReadLine() to get user input. This is what you do in your code. There are better ways to do this but following will solve your problem.Also you need to perform validation as well.
for (int i = 0; i < array.Length; i++)
{
Console.WriteLine("Enter in a name and score: ");
string userInput = Console.ReadLine();
string[] parsedInput;
parsedInput = userInput.Split(' ');
string name = parsedInput[0];
int score = int.Parse(parsedInput[1]);
array[i] = score;
}
Why you need to split array in to two arrays on containing names and other containing score. Its better to create a structure having String field for name and integer field for score and write Comparator for sorting the Array containing elements of this Data structure type and sort them.
It will solve all your problems and that too efficiently.
Not many data integrity checks in the methods you are using, but here are the extensions I use to split arrays or any type of enumerable. I have not tested these all that much, so I cannot guarantee that they will work. I have removed all my input validation, but I suggest you add those back your own way.
public static List<List<T>> Split<T>(this IEnumerable<T> collection, Int32 groupSize)
{
var collectionList = collection.ToList();
if (groupSize > collectionList.Count)
groupSize = collectionList.Count;
var chunks = new List<List<T>>();
while (collectionList.Any())
{
var chunk = collectionList.Take(groupSize);
chunks.Add(chunk.ToList());
collectionList = collectionList.Skip(groupSize).ToList();
}
return chunks;
}
public static List<List<T>> Split<T>(this IEnumerable<T> collection, Func<T, Boolean> splitFunction)
{
var collectionList = collection.ToList();
if (collectionList.IsNullOrEmpty())
return new List<List<T>>();
var indices = collectionList.FindIndices(splitFunction); // Custom method that searches for the indices that satisfy the predicate and returns the index of each matching item in the list.
if (indices.IsNullOrEmpty()) // equivalent to indices == null || !indices.Any()
return new List<List<T>> { collectionList };
var chunks = new List<List<T>>();
var lastIndex = 0;
if (indices[0] > 0)
{
chunks.Add(collectionList.Take(indices[0]).ToList());
lastIndex = indices[0];
}
for (var i = 1; i < indices.Count; i++)
{
var chunkSize = indices[i] - lastIndex;
var chunk = collectionList.Skip(lastIndex).Take(chunkSize).ToList();
if (chunk.IsNullOrEmpty())
{
break;
}
chunks.Add(chunk);
lastIndex = indices[i];
}
if (collectionList.Count - lastIndex > 0)
{
var lastChunk = collectionList.Skip(lastIndex).ToList();
chunks.Add(lastChunk);
}
return chunks;
}

c# parallel arrays data from text file

Here's the problem: Index was outside the bounds of the array. Assignment: Write a program that determines the number of students who can still enroll in a given class. Design your solution using parallel arrays. Test your solution by retrieving the following data from a text file. Define a exception class for this problem if the current enrollment exceeds the maximum enrollment by more than three. Halt the program and display a message indicating which course is over-enrolled.
Here's the original code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
private static string[] classes = { "CS150", "CS250", "CS270", "CS300", "CS350" };
private static int[] currentEnrolled = { 18, 11, 9, 4, 20 };
private static int[] maxEnrollment = { 20, 20, 20, 20, 20 };
private static int currentEnrollment()
{
int enrolled = 0;
foreach (int i in currentEnrolled)
{
enrolled += i;
}
return enrolled;
}
private static void listClasses()
{
foreach (string i in classes)
{
Console.WriteLine("Class: {0}", i);
}
}
private static void ClassStatus()
{
for (int i = 0; i < currentEnrolled.Length; i++)
{
Console.WriteLine("Class: {0}, Max: {1}, Current: {2}, remaining: {3}", classes[i], maxEnrollment[i], currentEnrolled[i], maxEnrollment[i] - currentEnrolled[i]);
}
}
static void Main(string[] args)
{
Console.WriteLine("Currently Enrolled: {0}", currentEnrollment());
ClassStatus();
Console.ReadKey(false);
}
}
}
Now, I've been editing the above code to take a text file instead, however I get an error. Here's what I'm working with:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
private static string[] classes = new string[900];
private static int[] currentEnrolled = new int[900];
private static int[] maxEnrollment = new int[900];
private static int currentEnrollment()
{
int enrolled = 0;
foreach (int i in currentEnrolled)
{
enrolled += i;
}
return enrolled;
}
private static void listClasses()
{
foreach (string i in classes)
{
Console.WriteLine("Class: {0}", i);
}
}
private static void ClassStatus()
{
for (int i = 0; i < currentEnrolled.Length; i++)
{
Console.WriteLine("Class: {0}, Max: {1}, Current: {2}, remaining: {3}", classes[i], maxEnrollment[i], currentEnrolled[i], maxEnrollment[i] - currentEnrolled[i]);
}
}
static void Main(string[] args)
{
string[] lines = File.ReadAllLines("classes.txt");
int i = 0;
foreach (string line in File.ReadAllLines("classes.txt"))
{
string[] parts = line.Split(',');
while (i < 900 && i < parts.Length)
{
classes[i] = parts[1];
currentEnrolled[i] = int.Parse(parts[2]);
maxEnrollment[i] = int.Parse(parts[3]);
}
i++;
}
Console.WriteLine("Currently Enrolled: {0}", currentEnrollment());
ClassStatus();
Console.ReadKey(false);
}
}
}
Some of the components used in the above code were taken from this article: Splitting data from a text file into parallel arrays
Text file looks like this:
CS150,18,20
CS250,11,20
CS270,32,25
CS300,4,20
CS350,20,20
Any assistance will be appreciated. And yes, this is an assignment. Programming is most definitely not my strong suit.
There seem to be multiple problems with your while loop.
First, parts.Length will always be 3, since you have 2 commas and split on that. So the condition i < 900 && i < parts.Length does not really make sense, it's like i < 900 and i < 3, so it will always stop at 3. The intent is not really clear here, I think you meant to loop on each 900 values, but fi soforeach already does that for you.
Next, since there's 3 parts and C# arrays are 0-based, it should be parts[0], parts[1] and parts[2]. That's what causing your 'out of range' exception.
Finally, i++; should be in your while loop. If you leave it outside, you will loop forever as the index will never increase.
Basically, it should be something like this :
while (i < 900)
{
classes[i] = parts[0];
currentEnrolled[i] = int.Parse(parts[1]);
maxEnrollment[i] = int.Parse(parts[2]);
i++;
}
Again, the 900 is not really clear since you don't have 900 values per line (remember you're in a foreach). In my opinion you might as well scratch all that and redo it carefully.
What you need to do, is the following :
Read the file and store all the lines
Foreach line do:
Split the line in 3 parts
Store each separate part
Write results
For the "custom exception" part, you can add:
For the length of currentEnrollment do:
If currentEnrollment at current index is superior than maxEnrollment at current index do:
Throw a new exception with the className at current index

How can multiple IndexOf be faster than raw iteration?

string s = "abcabcabcabcabc";
var foundIndexes = new List<int>();
The question came from the discussion here. I was simply wondering
How can this:
for (int i = s.IndexOf('a'); i > -1; i = s.IndexOf('a', i + 1))
foundIndexes.Add(i);
Be better than this :
for (int i = 0; i < s.Length; i++)
if (s[i] == 'a') foundIndexes.Add(i);
EDIT : Where all does the performance gain come from?
I did not observe that using IndexOf was any faster than direct looping. Honestly, I don't see how it could be because each character needs to be checked in both cases. My initial results were this:
Found by loop, 974 ms
Found by IndexOf 1144 ms
Edit: After running several more times I've noticed that you must run release (ie with optimizations) to see my result above. Without optimizations, the for loop is indeed slower.
The benchmark code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Text;
using System.IO;
using System.Diagnostics;
namespace Test
{
public class Program
{
public static void Main(string[] args)
{
const string target = "abbbdbsdbsbbdbsabdbsabaababababafhdfhffadfd";
// Jit methods
TimeMethod(FoundIndexesLoop, target, 1);
TimeMethod(FoundIndexesIndexOf, target, 1);
Console.WriteLine("Found by loop, {0} ms", TimeMethod(FoundIndexesLoop, target, 2000000));
Console.WriteLine("Found by IndexOf {0} ms", TimeMethod(FoundIndexesIndexOf, target, 2000000));
}
private static long TimeMethod(Func<string, List<int>> method, string input, int reps)
{
var stopwatch = Stopwatch.StartNew();
List<int> result = null;
for(int i = 0; i < reps; i++)
{
result = method(input);
}
stopwatch.Stop();
TextWriter.Null.Write(result);
return stopwatch.ElapsedMilliseconds;
}
private static List<int> FoundIndexesIndexOf(string s)
{
List<int> indexes = new List<int>();
for (int i = s.IndexOf('a'); i > -1; i = s.IndexOf('a', i + 1))
{
// for loop end when i=-1 ('a' not found)
indexes.Add(i);
}
return indexes;
}
private static List<int> FoundIndexesLoop(string s)
{
var indexes = new List<int>();
for (int i = 0; i < s.Length; i++)
{
if (s[i] == 'a')
indexes.Add(i);
}
return indexes;
}
}
}
IndexOf(char value, int startIndex) is marked with the following attribute: [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")].
Also, the implementation of this method is most likely optimized in many other ways, probably using unsafe code, or using more "native" techniques, say, using the native FindNLSString Win32 function.

how to point to back of generic list c#

Is there a way to point to the last item added to a generic list in c# ? Like the back() for a vector in c++
If you're using the 3.5 framework
using System.Linq;
using System.Collections.Generic;
public static class Program {
public static void Main() {
Console.WriteLine(new List<int> { 1, 2, 3 }.Last()); // outputs - 3
}
}
List<int> myList = new List<int>();
for( int i = 0; i < 5; i++ )
{
myList.Add (i);
}
Console.WriteLine (String.Format ("Last item: {0}", myList[myList.Count - 1]));
list.Last() ?

Categories

Resources