Comparing Generic Values - c#

So i wanted to make a generic method that makes you an array with a specific length that you insert into and it sorts it at the same time.
so i was transfering it from int to generic T and i stumbled into a problem while trying to compare 2 variables of T.
this is the code so far:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication7
{
class Program
{
public static T[] insertWhileSorting<T>(int x)
{
T[] arr = new T[x];
for (int i = 0, k; i < arr.Length; i++)
{
T value = (T)Convert.ChangeType(Console.ReadLine(), typeof(T));
for (k = i; k > 0 && value.CompareTo(arr[k - 1]) < 0; --k) arr[k] = arr[k - 1];
arr[k] = value;
}
return arr;
}
static void Main(string[] args)
{
int[] arr = insertWhileSorting<int>(5);
Console.WriteLine(string.Join(", ", arr));
}
}
}
and yes i know(i think)that simply inserting the values into an array and then sorting it is better but i'm doing it for an assignment

You would need to assert that the type T as implemented IComparable<T>. Using the where key word you can restrict the type T with a condition that T has to implement IComparable<T>:
public static T[] insertWhileSorting<T>(int x) where T: IComparable<T>
IComparable demands that the class in question implements the method CompareTo. Now the compiler should stop complaining that
"T" does not contain a definition for "CompareTo" and cannot find an extension method "CompareTo"
EDIT:
this line can get you easily into trouble:
T value = (T)Convert.ChangeType(Console.ReadLine(), typeof(T));
because the user can type simply a string like "break" which would result in an FormatException if you initially called it like this:
int [] adda = insertWhileSorting<int>(5);
You can put this whole conversion and sorting routine into a try catch clause and give a warning when it crashes:
for (int i = 0, k; i < arr.Length; i++)
{
try
{
T value = (T)Convert.ChangeType(Console.ReadLine(), typeof(T));
for (k = i; k > 0 && value.CompareTo(arr[k - 1]) < 0; --k) arr[k] = arr[k - 1];
arr[k] = value;
}
catch (Exception ex)
{
Console.WriteLine("That stuff was not convertible!");
Console.WriteLine("Error: " + ex.Message);
}
}

Related

Return all powers of 2 less then n in C# [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
For a given number n, I need to return all powers of 2 less than n, as a string in a way that elements are separated with "-". If n < 2, it needs to return an empty string.
For example:
n = 20 => 1-2-4-8-16
n = 8 => 1-2-4
I'm a beginner, so any help would be much appreciated! :)
EDIT: this is not working
using System;
class N
{
static int[] powerof2(int n)
{
int[] array = new int[n];
if (n < 2)
return new int[0];
for (int i = 0; i < 8 * sizeof(uint); i++)
{
int curr = 1 << i;
if (curr > n)
break;
array[i] = curr;
}
return array;
public override string ToString()
{
for (int i = 0; i < array.length; i++)
return (array[i] + "-");
}
}
static public void Main ()
{
int n = 10;
Console.WriteLine(powerof2(n).ToString());
}
}
You need to run the for loop with the following rule
for (int i = 1; i < n; i *= 2)
Whole solution
class Program
{
static void powerof2(int n)
{
if (n < 2)
Console.WriteLine(string.Empty);
for (int i = 1; i < n; i *= 2)
{
if (i > 1)
Console.Write("-");
Console.Write(i);
}
}
static void Main(string[] args)
{
powerof2(20);
}
Using iterator methods makes this case trivial (Fiddle):
using System;
using System.Collections.Generic;
public class Program
{
public static IEnumerable<int> GetPowersOf2(int maxN)
{
for (int p = 1; p < maxN; p *= 2)
{
yield return p;
}
}
public static void Main(string[] args)
{
IEnumerable<int> powersOf2LessThan20 = GetPowersOf2(20);
Console.WriteLine(string.Join("-", powersOf2LessThan20));
}
}
I suppose this is what you're looking for:
class Program
{
public static string Pow2LessThan(ulong n)
{
if (n < 2)
return "";
// start with 2^0
string res = "1";
// try further
int p = 1;
ulong cnum = 2;
while (cnum < n)
{
res += "-" + cnum.ToString();
++p;
cnum = (ulong)(1 << p);
}
return res;
}
static void Main(string[] args)
{
ulong n = 20;
Console.WriteLine(Pow2LessThan(n));
Console.ReadLine();
}
}
The reason that it's not working is: you never access the class N in any way. The call should be
Console.WriteLine(N.powerof2(n).ToString());
^^
With that modification, you'll be notified that the method powerof2() is inaccessible due to its protection level. You need to make it at least internal like so:
internal static int[] powerof2(int n)
Next, note that you're missing a } for that method.
return array;
}
With that fixed, the compiler will tell you that you can't access array inside ToString(), because the scope of array is limited to powerof2(). Make the array a field of the class like
static int[] array;
Now, the compiler complains about array.length in ToString(). Fix that by capitalizing Length.
Mistake number 6: ToString() will return in the first iteration of the loop. It will not return anything if array.Length is 0. The function should look a little bit like this:
public override string ToString()
{
string result = "";
for (int i = 0; i < array.Length; i++)
result += array[i] + "-";
return result;
}
Now, this will still not work, because the main method calls ToString() on the return value of powerof2(), which is of type int[] and not of type N. That's because your stuff is static. Make it non-static instead and create an instance of N.
static public void Main ()
{
var n = new N();
n.powerof2(10);
Console.WriteLine(n.ToString());
}
With 7 issues fixed, the output is now 1-2-4-8-0-0-0-0-0-0-, so there's still stuff to fix. Maybe you get a little bit of a feeling why everyone proposes a totally different solution.
What else to fix:
the output of course is still incorrect.
if someone inputs 4000000000 as the number, you certainly don't want to allocate 4 GB of RAM in the array.
Why allocate an array at all and not construct the string right away?
Why 8*sizeof(uint)? You can't shift more often than sizeof(uint).
class Program
{
static string powerof2(int n)
{
var str="1" ;
if (n < 2)
return "" ;
else
{
var i=1;
while(Math.Pow(i, 2)<n)
{
str+="-" +Math.Pow(2, i);
i++;
}
return str;
}
}
static void Main(string[] args)
{
powerof2(50);
}
}

How can I return my count integer to main from my function?

I'm pretty new to programming and trying to get this project to return a value to main from the function, however i'm a bit sketchy on passing data and the formatting.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace most_frequent_int
{
class Program
{
static void Main(string[] args)
{
mostFreq(new int[] {1,5,2,5,24,6,5});
}
static void mostFreq(int[] number)
{
int element = 0;
int count = 0;
for (int j = 0; j < number.Length; j++)
{
int tempElement = number[j];
int tempCount = 0;
for (int p = 0; p <number.Length; p++)
{
if (number[p] == tempElement)
{
tempCount++;
}
if (tempCount > count)
element = tempElement;
{
count = tempCount;
}
}
}
Console.WriteLine("The most frequent element is: " + element + " and appears " + count + " times.");
}
}
}
I'm trying to take the value stored in count in the method and return it to main to be used again there, but i'm racking my head on how to do so.
Really sorry if this is a completely stupid question but any help is appreciated.
First change the return type of your method to what you want: (an integer)
static int mostFreq(int[] number)
{
//...
}
In your mostFreq method, use the return keyword to pass the value you need to return that way:
static int mostFreq(int[] number)
{
//...
return count;
}
Then catch the value in main and use it:
static void Main(string[] args)
{
int count = mostFreq(new int[] {1,5,2,5,24,6,5});
Console.WriteLine("Count is " + count);
}
The easiest way to communicate from a function to its caller is probably just to return the value, such as with the following example:
static int return42() {
return 42;
}
And then, in main:
int fortytwo = return42();
In other words, it entails:
ensuring the function signature returns a real type rather than void;
actually returning the desired value from the function; and
having the caller pick up the return value for later use.
Unfortunately, you have two values you wish to return. While you could return the string itself and just print it in main, it doesn't really give you the adaptability if you want to use the count and value in other ways, from other pieces of code.
That is, after all, the main reason for putting things into functions, so that common code can be called from many places.
A more adaptable way could use a number of options, such as:
using tuples, which are a class containing multiple objects;
returning an array if the variables are of the same type; or
using out parameters in the function for secondary return values.
Using that last one, for example, would entail something like (with your actual code replaced with some magic function calls for demo purposes):
static void mostFreq(int[] number, [out] int value) {
value = MagicMostCommonValueInArray();
return MagicCountOfThatValue();
}
And then, in main:
int element;
int count = mostFreq(new int[] {1,5,2,5,24,6,5}, out element);
Console.WriteLine(
"The most frequent element is: " + element +
" and appears " + count + " times.");
My advice would be to use that method rather than returning a single string.
It should be:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace most_frequent_int
{
class Program
{
static void Main(string[] args)
{
string result = mostFreq(new int[] {1,5,2,5,24,6,5});
Console.WriteLine(result);
}
static string mostFreq(int[] number)
{
int element = 0;
int count = 0;
for (int j = 0; j < number.Length; j++)
{
int tempElement = number[j];
int tempCount = 0;
for (int p = 0; p <number.Length; p++)
{
if (number[p] == tempElement)
{
tempCount++;
}
if (tempCount > count)
element = tempElement;
{
count = tempCount;
}
}
}
return "The most frequent element is: " + element + " and appears " + count + " times."
}
}

How to write overloaded generic extension methods for T[], T[][] without ambiguity?

I want to write extension methods for converting a vector and matrix into string. I did this in the following way.
For Vector
public static string GetString<T>(this T[] SourceMatrix, string ColumnDelimiter = " ")
{
try
{
string result = "";
for (int i = 0; i < SourceMatrix.GetLength(0); i++)
result += SourceMatrix[i] + ColumnDelimiter;
return result;
}
catch (Exception ee) { return null; }
}
For Matrix
public static string GetString<T>(this T[][] SourceMatrix, string ColumnDelimiter = " ", string RowDelimiter = "\n")
{
try
{
string result = "";
for (int i = 0; i < SourceMatrix.GetLength(0); i++)
{
for (int j = 0; j < SourceMatrix[i].GetLength(0); j++)
result += SourceMatrix[i][j] + "" + ColumnDelimiter;
result += "" + RowDelimiter;
}
return result;
}
catch (Exception ee) { return null; }
}
Now i am using following code which causes ambiguity.
List<double[]> Patterns= GetPatterns();
Patterns.ToArray().GetString();
Error
Error 5 The call is ambiguous between the following methods or properties:
'MatrixMathLib.MatrixMath.GetString<double[]>(double[][], string)' and
'MatrixMathLib.MatrixMath.GetString<double>(double[][], string, string)'
Can anyone suggest me to write these extension methods correctly.
Thanks in advance.
There is nothing wrong with your methods. It is the compiler that can't choose between them.
As you can see in the error message, the compiler could assume T to be double[] and match the first method, or double and match the second one. This will be solved by explicitly mentioning which method you want to use:
Patterns.ToArray().GetString<double>();
You can either omit the default values or state the type of T in the function call
The compiler can't tell whether you want to call GetString<double[]> or GetString<double> because both methods fit the invocation.
The easiest way to solve that is to simply change one of the names (i.e. GetArrayString<T>). A better solution IMO is to have only 1 method that solves both cases like this one:
public static string Join<T>(this T[] sourceMatrix, string columnDelimiter = " ", string rowDelimiter = "\n")
{
if (sourceMatrix.Length == 0)
{
return string.Empty;
}
if (sourceMatrix[0] as Array == null)
{
return string.Join(columnDelimiter, sourceMatrix);
}
var rows = new List<string>();
foreach (T item in sourceMatrix)
{
var array = item as Array;
var row = "";
for (int j = 0; j < array.GetLength(0); j++)
row += array.GetValue(j) + columnDelimiter;
rows.Add(row);
}
return string.Join(rowDelimiter, rows);
}
Usage:
int[] a = {1, 2, 3};
int[] b = { 1, 2, 4 };
int[][] c = {a, b};
Console.WriteLine(a.Join());
Console.WriteLine();
Console.WriteLine(c.Join());
Output:
1 2 3
1 2 3
1 2 4
Note: This only solves for 1-2 dimensions, but can easily be generalized to n dimensions.

Why can't I Selection Sort this library?

I'm trying to use Selection Sort for a library of books so that it sorts them alphabetically, however I can't get it to work.
SelectionSort(library); doesn't work but SelectionSort(titles); does, any ideas? Thanks :)
Here is the full code:
using System;
using System.Collections.Generic;
using System.Text;
namespace BookSortingEx
{
class Program
{
static void swap<T>(ref T x, ref T y)
{
//swapcount++;
T temp = x;
x = y;
y = temp;
}
static void printArray(string[] a)
{
for (int i = 0; i < a.Length; i++)
{
Console.Write(a[i] + ",");
}
Console.WriteLine();
}
static bool IsInOrder<T>(T[] a) where T : IComparable
{
for (int i = 0; i < a.Length - 1; i++)
{
if (a[i].CompareTo(a[i + 1]) > 0)
return false;
}
return true;
}
static void Main(string[] args)
{
string[] array1 = { "Fred", "Zoe", "Angela", "Umbrella", "Ben" };
string[] titles = {"Writing Solid Code",
"Objects First","Programming Gems",
"Head First Java","The C Programming Language",
"Mythical Man Month","The Art of Programming",
"Coding Complete","Design Patterns",
"Problem Solving in Java"};
string[] authors = { "Maguire", "Kolling", "Bentley", "Sierra", "Richie", "Brooks", "Knuth", "McConnal", "Gamma", "Weiss" };
string[] isbns = { "948343", "849328493", "38948932", "394834342", "983492389", "84928334", "4839455", "21331322", "348923948", "43893284", "9483294", "9823943" };
Book[] library = new Book[10];
for (int i = 0; i < library.Length; i++)
{
library[i] = new Book(isbns[i], titles[i], authors[i]);
}
**DOESNT WORK - // SelectionSort(library);**
SelectionSort(titles);
printArray(titles);
foreach (Book book in library)
{
Console.WriteLine(" {0} ", book);
}
Console.WriteLine();
Console.ReadKey();
}
static public void SelectionSort(string[] a)
{
for (int i = 0; i < a.Length - 1; i++)
{
int smallest = i;
for (int j = i + 1; j < a.Length; j++)
{
if (a[j].CompareTo(a[smallest]) < 0)
smallest = j;
}
swap(ref a[i], ref a[smallest]);
}
}
}
}
Your method expects a string[], but you're giving it a Book[]
You'll want to change the implementation of SelectionSort to support Comparable Collections, as well as have Book implement the IComparable interface.
public class Book : IComparable
{
// Implementation
public int CompareTo(Book otherBook)
{
// Implementation
}
}
static public void SelectionSort<T>(IList<T> a) where T : IComparable
{
// Implementation
}
The advantage of this approach, is that you won't have to create a different version of SelectionSort for every kind of object collection you'll want to sort.
Because SelectionSort takes as an argument an array of type string and you are passing it an array of type Book. SelectionSort(titles) works because titles is an array of type string.
You need to write a method that takes an array of type Book
static public void SelectionSort(Book[] books)
and if you haven't done this already you probably need to define a CompareTo method in your Book class, so your sorting algorithm can figure out how to sort books.

mergesort - with an insignificant change throws SystemInvalidOperationException

A very strange thing occured in my program. Here is the simplified code.
class Program
{
static void Main(string[] args)
{
ArrayList numbers = new ArrayList();
numbers.Add(1);
numbers.Add(3);
numbers.Add(4);
numbers.Add(2);
var it = Sorts.MergeSort((ArrayList)numbers.Clone());
Sorts.PrintArray(it, "mergesort");
Console.WriteLine("DONE");
Console.ReadLine();
}
}
public static class Sorts
{
public static ArrayList BubbleSort(ArrayList numbers)
{
bool sorted = true;
for (int i = 0; i < numbers.Count; i++)
{
for (int j = 1; j < numbers.Count; j++)
{
if ((int)numbers[j - 1] > (int)numbers[j])
{
int tmp = (int)numbers[j - 1];
numbers[j - 1] = numbers[j];
numbers[j] = tmp;
sorted = false;
}
}
if (sorted)
{
return numbers;
}
}
return numbers;
}
public static ArrayList MergeSort(ArrayList numbers, int switchLimit = 3)
{
//if I use this if - everything works
if (numbers.Count <= 1)
{
// return numbers;
}
//the moment I use this condition - it throws SystemInvalidOperationException in function Merge in the line of a "for"-loop
if (numbers.Count <=switchLimit)
{
return Sorts.BubbleSort(numbers);
}
ArrayList ret = new ArrayList();
int middle = numbers.Count / 2;
ArrayList L = numbers.GetRange(0, middle);
ArrayList R = numbers.GetRange(middle, numbers.Count - middle);
L = MergeSort(L);
R = MergeSort(R);
return Merge(L, R);
}
private static ArrayList Merge(ArrayList L, ArrayList R)
{
ArrayList ret = new ArrayList();
int l = 0;
int r = 0;
for (int i = 0; i < L.Count + R.Count; i++)
{
if (l == L.Count)
{
ret.Add(R[r++]);
}
else if (r == R.Count)
{
ret.Add(L[l++]);
}
else if ((int)L[l] < (int)R[r])
{
ret.Add(L[l++]);
}
else
{
ret.Add(R[r++]);
}
}
return ret;
}
//---------------------------------------------------------------------------------
public static void PrintArray(ArrayList arr, string txt = "", int sleep = 0)
{
Console.WriteLine("{1}({0}): ", arr.Count, txt);
for (int i = 0; i < arr.Count; i++)
{
Console.WriteLine(arr[i].ToString().PadLeft(10));
}
Console.WriteLine();
System.Threading.Thread.Sleep(sleep);
}
}
There is a problem with my Sorts.MergeSort function.
When I use it normally (take a look at the first if-condition in a function - all works perfectly.
But the moment when I want it to switch to bubblesort with smaller input (the second if-condition in the function) it throws me an SystemInvalidOperationException. I have no idea where is the problem.
Do you see it?
Thanks. :)
Remark: bubblesort itself works - so there shouldn't be a problem in that sort...
The problem is with your use of GetRange:
This method does not create copies of the elements. The new ArrayList is only a view window into the source ArrayList. However, all subsequent changes to the source ArrayList must be done through this view window ArrayList. If changes are made directly to the source ArrayList, the view window ArrayList is invalidated and any operations on it will return an InvalidOperationException.
You're creating two views onto the original ArrayList and trying to work with both of them - but when one view modifies the underlying list, the other view is effectively invalidated.
If you change the code to create copies of the sublists - or if you work directly with the original list within specified bounds - then I believe it'll work fine.
(As noted in comments, I'd also strongly recommend that you use generic collections.)
Here's a short but complete program which demonstrates the problem you're running into:
using System;
using System.Collections;
class Program
{
static void Main()
{
ArrayList list = new ArrayList();
list.Add("a");
list.Add("b");
ArrayList view1 = list.GetRange(0, 1);
ArrayList view2 = list.GetRange(1, 1);
view1[0] = "c";
Console.WriteLine(view2[0]); // Throws an exception
}
}
on this line R = MergeSort(R); you alter the range of numbers represented by L. This invalidates L. Sorry I have to go so can't explain any further now.

Categories