I see that there is a similar question for C++. Does anyone know why this method works when the method is non-generic, but as soon as I make it generic, the random number portion of code fails?
Error: Cannot implicitly convert type int to 'T'. If I can't use generics, I will have to rewrite the same function over and over for each different length of array.
public void fillGenericArray<T>(T[] inputArray) where T : IComparable
{
var randomNumb1 = new Random();
for (int i = 0; i < inputArray.Length - 1; i++)
{
Console.WriteLine($"{inputArray[i] = randomNumb1.Next(1, 501)},");
}
}
I had to look twice at this, but here's the issue:
Because inputArray is an 'array of type T'
then even though i is an int the expression
inputArray[i]
returns a type T not a type int.
And so, conversely, a type T must be assigned to it.
A generic method like this might achieve your goal:
public static void fillGenericArray<T>(T[] inputArray)
{
for (int i = 0; i < inputArray.Length; i++)
{
// Where T has a CTor that takes an int as an argument
inputArray[i] = (T)Activator.CreateInstance(typeof(T), Random.Next(1, 501));
}
}
(Thanks to this SO post for refreshing my memory about instantiating T with arguments.)
You could also use Enumerable.Range() to get the same result without writing a method at all:
// Generically, for any 'SomeClass' with a CTor(int value)
SomeClass[] arrayOfT =
Enumerable.Range(1, LENGTH).Select(i => new SomeClass(Random.Next(1, 501)))
.ToArray();
(Slightly Modified with help from this SO post) - see the answer using Enumerable.Range().
Here is a test runner:
class Program
{
static Random Random { get; } = new Random();
const int LENGTH = 10;
static void Main(string[] args)
{
Console.WriteLine();
Console.WriteLine("With a generic you could do this...");
SomeClass[] arrayOfT;
arrayOfT = new SomeClass[LENGTH];
fillGenericArray<SomeClass>(arrayOfT);
Console.WriteLine(string.Join(Environment.NewLine, arrayOfT.Select(field=>field.Value)));
Console.WriteLine();
Console.WriteLine("But perhaps it's redundant, because Enumerable is already Generic!");
arrayOfT = Enumerable.Range(1, LENGTH).Select(i => new SomeClass(Random.Next(1, 501))).ToArray();
Console.WriteLine(string.Join(Environment.NewLine, arrayOfT.Select(field => field.Value)));
// Pause
Console.WriteLine(Environment.NewLine + "Any key to exit");
Console.ReadKey();
}
public static void fillGenericArray<T>(T[] inputArray)
{
for (int i = 0; i < inputArray.Length; i++)
{
inputArray[i] = (T)Activator.CreateInstance(typeof(T), Random.Next(1, 501));
}
}
class SomeClass
{
public SomeClass(int value)
{
Value = value;
}
public int Value { get; set; }
}
}
Clone or Download this example from GitHub.
There is no reason to use generics. Just replace T with int and you will have function that does what you want (based on your question and comment below it).
EDIT: From your comment it seems you misunderstand the purpose of generics. The non-generic function WILL work for all lengths of the array.
And to answer why the change to generics fails. You are trying to assign int to generic type T which can be anything and compiler will not allow such a cast.
Related
I have a problem with code.
I receive an error CS0311: The type 'object' cannot be used as type parameter 'T' in the generic type or method 'GenericMethods.search(T[], T)'. There is no implicit reference conversion from 'object' to 'System.IComparable'.
Task:
Create a console app and write a generic method, Search [ int Search( T [ ] dataArray, T searchKey) ]
that searches an array using linear search algorithm.
a) Method Search should compare the search key with each element in the array until the search key
is found or until the end of the array is reached.
b) If the search key is found, return/display its location in the array (i.e. its index value); otherwise
return -1.
c) You need to populate the array with random values. ( int values – between 10 and 49, double
values between 50 and 99, char values between a and z). The size of array as 10.
d) Test this method by passing two types of arrays to it. (an integer array and a string array) Display
the generated values so that the user knows what values he/she can search for.
[Hint: use (T: IComparable) in the where clause for method Search so that you can use method CompareTo() to
compare the search key to the elements in the array]
My code:
using System;
using System.Collections.Generic;
namespace LinearSearch
{
class GenericMethods
{
static void Main(string[] args)
{
object[] dataArray = new object[10];
Random random = new Random();
for (int i = 0; i < dataArray.Length; i++)
{
int randomType = random.Next(1, 3);
if (randomType == 1)
{
char randomChar = (char)random.Next('a', 'z');
dataArray[i] = randomChar;
}
else if (randomType == 2)
{
double randomDouble = random.Next(50, 99);
dataArray[i] = (int)randomDouble;
}
else
{
int randomInt = random.Next(10, 49);
dataArray[i] = randomInt;
}
}
Console.WriteLine("Generated array is: ");
Console.WriteLine(string.Join(" ", dataArray));
Console.WriteLine("Please, enter number from 10 to 99 or char from A to Z");
object userInput = Console.ReadLine();
Console.WriteLine(userInput);
Console.WriteLine($"Location of search value {userInput}: {search(dataArray, userInput)}");
}//end Main method
private static int search<T>(T[] dataArray, T searchKey) where T : IComparable<T>
{
// default to -1 so that we can determine the search is successful when it becomes a positive value
int arrayPosition = -1;
for (int x = 0; x < dataArray.Length; x++)
{
T arrayElement = dataArray[x];
// Console.WriteLine($"CompareTo result: {searchValue.CompareTo(arrayElement)}");
if (searchKey.CompareTo(arrayElement) == 0)
{
// value is found
arrayPosition = x;
break;
}
}
return arrayPosition;
} // end searchValue
}
}
Could you please help me to fix this problem? I am new in C#..
Instead of declaring dataArray as an object[] declare it as an IComparable[]. You wrote the type constraint limiting your generic type T to IComparable. object does not implement IComparable, so it is not a valid type
Lucky me, I always write generic searches for my code. For other search methods with Generics in C#, you can find them here.
public static int LinearSearch<T>(T[] array, T item) // O(n)
{
for (int i = 0; i < array.Length; i++)
/* array[i] == item */
if (Comparer<T>.Default.Compare(array[i], item) == 0)
return i;
return -1; // Not found
}
You must import 'System.Collections.Generic' in your file.
using System.Collections.Generic;
I found solution
string[] resultArray = Array.ConvertAll(dataArray, x => x.ToString());
After that code works
Now, I may get negative points because perhaps somewhere in vast internet there is already an answer to this but I tried to look for it and I simply couldnt find it.
The gist of the problem is that HackerRanks wants you to create an array with a size decided by the user, then have the user add its values (integers) and finally have the program sum its values.
There are plenty of ways to do it and I already know how to but my problem is that I just can't understand Hackerrank's code sample in C# it gave me. I commented the parts I don't understand, which is most of it:
static int simpleArraySum(int n, int[] ar) {
// Complete this function
int sum = 0;
foreach( var item in ar){
sum += item;
}
return sum;
}
static void Main(String[] args) {
//I know what this does
int n = Convert.ToInt32(Console.ReadLine());
//I am lost here, just why create a string array and add the split method?
string[] ar_temp = Console.ReadLine().Split(' ');
//I dont understand here neither, what is it converting? What is the parse for?
int[] ar = Array.ConvertAll(ar_temp,Int32.Parse);
//Why send the n when all you need is the array itself?
int result = simpleArraySum(n, ar);
Console.WriteLine(result);
}
I know some people hate HackerRank, and honestly, I do too but it does gives me some nice ways to test my limited skills in coding with c# and testing my logic. So, if there are better sites that helps you test your logic as a CS please share them with me.
Here is the code I made to solve this problem in Visual Studio but for some stupid reason Hackerrank wont accept it unless I make custom inputs:
//This code can be potentially shorter using the code commented further below.
//For practice's sake, it was made longer.
static int simpleArraySum(int[] arr_temp)
{
int total = 0;
foreach (var item in arr_temp)
{
total += item;
}
return total;
}
static void Main(String[] args)
{
int n = Convert.ToInt32(Console.ReadLine());
int[] arr_temp = new int[n];
for (int i = 0; i < n; i++)
{
arr_temp[i] = Convert.ToInt32(Console.ReadLine());
}
int result = simpleArraySum(arr_temp);
//int result = arr_temp.Sum();
Console.WriteLine(result);
Console.ReadLine();
}
You need to convert to string array since if you're on the main method, all it gets are string values from the argument list. To get the sum then you need to convert the string into a usable number / integer.
I agree that it doesn't make sense to send the first argument n in simpleArraySum because n is simply unused.
as for the part int[] ar = Array.ConvertAll(ar_temp,Int32.Parse); it simply tries to take in all the integers into the array. It is also risky because if you accidentally pass in a string then it will throw an error i.e. pass in "3 4 1 f" <- f will throw an exception, unless this is the desired behaviour.
Personally I think the main method should not be interested in getting involved too much with the data, the heavy lifting should be done in the methods. The better version perhaps would be to modify simpleArraySum and refactor that line in like:
static int simpleArraySum(string input)
{
String[] fields = input.Split(null);
List<int> vals = new List<int>();
foreach (string i in fields)
{
var j = 0;
if (Int32.TryParse(i, out j)) vals.Add(j);
}
int sum = 0;
foreach (var item in vals)
{
sum += item;
}
return sum;
}
I introduced the use of generic list because it's more readable if not cleaner, although the use of List might look overkill to some programmers and might not be as light weight as just using an array, hence on the other hand you can easily stick to using arrays except that it needs to be initialized with the length i.e. int[] vals = new int[fields.Length]; Roughly:
static int simpleArraySum(string input)
{
String[] fields = input.Split(null);
int[] vals = new int[fields.Length];
for (int i = 0; i < fields.Length; i++)
{
var j = 0;
if (Int32.TryParse(fields[i], out j)) vals[i] = j;
}
int sum = 0;
foreach (var item in vals)
{
sum += item;
}
return sum;
}
here my code i hope that helps
static int simpleArraySum(int[] ar,int count) {
if (count > 0 && count <= 10000)
{
if (count == ar.Length)
{
if (!ar.Any(item => (item < 0 || item >= 10000)))
{
return ar.Sum();
}
}
}
return 0;
}
and in main
int arCount = Convert.ToInt32(Console.ReadLine());
int[] arr = Array.ConvertAll(Console.ReadLine().Split(' '), arTemp => Convert.ToInt32(arTemp));
int result = simpleArraySum(arr, arCount);
Console.WriteLine(result);
since Array.ConvertAll() takes a string and convert it to one type array
int or float for example
For users still looking for a 100% C# solution: In above mentioned coding websites do not modify the main function. The aim of the test is to complete the function via the online complier.
using System.Linq;
public static int simpleArraySum(List<int> ar)
{
int sum = ar.Sum();
return sum;
}
I need a function that works on any either real-valued or complex-valued array.
However, for the function itself, it is very convenient to work on a Complex[]-Array. Therefore I want to typecast any array which is not of type Complex[] (e.g. double[] or byte[] or int[]...) to Complex[].
I thought this might be a nice exercise for myself to write a small generic function:
private static Complex[] convertArrayToComplex<T>(T[] inpArr)
{
if (typeof(T) != typeof(Complex[]))
{
Complex[] inpArrC = new Complex[inpArr.Length];
for (int k = 0; k < inpArr.Length; k++)
{
inpArrC[k] = new Complex((double)(object)inpArr[k], 0);
}
return inpArrC;
} else
{
return inpArr; // Compiler-Error is here
}
}
Of course this does not work: I get the Compiler-Error telling me, that T[] cannot implicitly casted to Complex[]. I do understand this, but I do not see a way to achieve my goal in an elegant fashion.
Constraints: I know that inpArr is a numeric Array.
You can know the type is equal, but you still have to convince the compiler. Also, I would make the code clearer by using is instead of type checking:
private static Complex[] convertArrayToComplex<T>(T[] inpArr)
{
if (inpArr is Complex[])
{
return (Complex[])(object)inpArr;
}
Complex[] inpArrC = new Complex[inpArr.Length];
for (int k = 0; k < inpArr.Length; k++)
{
inpArrC[k] = new Complex(Convert.ToDouble(inpArr[k]), 0);
}
return inpArrC;
}
In my c# code I have a static method. Here is the code sample:
public class RandomKey
{
public static string GetKey()
{
Random rng = new Random();
char[] chars = new char[8];
for (int i = 0; i < chars.Length; i++)
{
int v = rng.Next(10 + 26 + 26);
char c;
if (v < 10)
{
c = (char)('0' + v);
}
else if (v < 36)
{
c = (char)('a' - 10 + v);
}
else
{
c = (char)('A' - 36 + v);
}
chars[i] = c;
}
string key = new string(chars);
key += DateTime.Now.Ticks.ToString();
return key;
}
}
I am calling this function from another Class's method.
Class SomeClass
{
Void SomeMethod()
{
for(int i=0; i<100; i++)
{
System.Diagnostics.Debug.WriteLine(i + "===>" + RandomKey.GetKey());
}
}
}
But now the problem is sometimes I am getting the same output from the static method though the function was called separately. Is there any wrong with my code?
The reason is that you are initializing the Random object inside the method.
When you call the method in close time proximity (like inside a loop), the Random object is initialized with the same seed. (see Matthew Watson's comment to find out why.)
To prevent that you should declare and initialize the Random object as a static field, like this:
public class RandomKey
{
static Random rng = new Random();
public static string GetKey()
{
// do your stuff...
}
}
You keep reinitializing the Random value. Move that out to a static field. Also you can format numbers in hex using ToString with a formatter.
Also, DateTime.Now is a bad idea. See this answer for a better way to allocate unique, timestamp values.
In the following program, DummyMethod always print 5. But if we use the commented code instead, we get different values (i.e. 1, 2, 3, 4). Can anybody please explain why this is happenning?
delegate int Methodx(object obj);
static int DummyMethod(int i)
{
Console.WriteLine("In DummyMethod method i = " + i);
return i + 10;
}
static void Main(string[] args)
{
List<Methodx> methods = new List<Methodx>();
for (int i = 0; i < 5; ++i)
{
methods.Add(delegate(object obj) { return DummyMethod(i); });
}
//methods.Add(delegate(object obj) { return DummyMethod(1); });
//methods.Add(delegate(object obj) { return DummyMethod(2); });
//methods.Add(delegate(object obj) { return DummyMethod(3); });
//methods.Add(delegate(object obj) { return DummyMethod(4); });
foreach (var method in methods)
{
int c = method(null);
Console.WriteLine("In main method c = " + c);
}
}
Also if the following code is used, I get the desired result.
for (int i = 0; i < 5; ++i)
{
int j = i;
methods.Add(delegate(object obj) { return DummyMethod(j); });
}
The problem is that you're capturing the same variable i in every delegate - which by the end of the loop just has the value 5.
Instead, you want each delegate to capture a different variable, which means declaring a new variable in the loop:
for (int i = 0; i < 5; ++i)
{
int localCopy = i;
methods.Add(delegate(object obj) { return DummyMethod(localCopy); });
}
This is a pretty common "gotcha" - you can read a bit more about captured variables and closures in my closures article.
This article will probably help you understand what is happening (i.e. what a closure is): http://blogs.msdn.com/oldnewthing/archive/2006/08/02/686456.aspx
If you look at the code generated (using Reflector) you can see the difference:
private static void Method2()
{
List<Methodx> list = new List<Methodx>();
Methodx item = null;
<>c__DisplayClassa classa = new <>c__DisplayClassa();
classa.i = 0;
while (classa.i < 5)
{
if (item == null)
{
item = new Methodx(classa.<Method2>b__8);
}
list.Add(item);
classa.i++;
}
foreach (Methodx methodx2 in list)
{
Console.WriteLine("In main method c = " + methodx2(null));
}
}
When you use the initial code it creates a temporary class in the background, this class holds a reference to the "i" variable, so as per Jon's answer, you only see the final value of this.
private sealed class <>c__DisplayClassa
{
// Fields
public int i;
// Methods
public <>c__DisplayClassa();
public int <Method2>b__8(object obj);
}
I really recommend looking at the code in Reflector to see what's going on, its how I made sense of captured variables. Make sure you set the Optimization of the code to ".NET 1.0" in the Option menu, otherwise it'll hide all the behind scenes stuff.
I think it is because the variable i is put to the heap (it's a captured variable)
Take a look at this answer.