I often work with arrays of int/float and other things on a regular basis in C# since they are faster (maybe?) than List. Currently I've got dozens of functions implemented per type:
/// <summary>
/// Checks if the array contains the given value.
/// </summary>
public static bool contains(int[] values, int value) {
for (int s = 0, sl = values.Length; s < sl; s++) {
if (values[s] == value) {
return true;
}
}
return false;
}
/// <summary>
/// Checks if the array contains the given value.
/// </summary>
public static bool contains(float[] values, float value) {
for (int s = 0, sl = values.Length; s < sl; s++) {
if (values[s] == value) {
return true;
}
}
return false;
}
Is there a way to implement these in a generic way? Or is that only possible if I use List<T>?
The System.Array type has a dizzying array of static methods that can help you search, arrange, sort etc your arrays. You definitely do not need to roll your own. These static methods (like Find, FindAll) also accept generic arguments. Here's the list, dumped with the aid of PowerShell:
Name Definition
---- ----------
AsReadOnly static System.Collections....
BinarySearch static int BinarySearch(ar...
Clear static void Clear(array ar...
ConstrainedCopy static void ConstrainedCop...
ConvertAll static TOutput[] ConvertAl...
Copy static void Copy(array sou...
CreateInstance static array CreateInstanc...
Equals static bool Equals(System....
Exists static bool Exists[T](T[] ...
Find static T Find[T](T[] array...
FindAll static T[] FindAll[T](T[] ...
FindIndex static int FindIndex[T](T[...
FindLast static T FindLast[T](T[] a...
FindLastIndex static int FindLastIndex[T...
ForEach static void ForEach[T](T[]...
IndexOf static int IndexOf(array a...
LastIndexOf static int LastIndexOf(arr...
ReferenceEquals static bool ReferenceEqual...
Resize static void Resize[T]([ref...
Reverse static void Reverse(array ...
Sort static void Sort(array arr...
TrueForAll static bool TrueForAll[T](...
Thanks #Servy for your corrections :
/// <summary>
/// Checks if the array contains the given value.
/// </summary>
public static bool Contains<T>(T[] values, T value) {
for (int s = 0, sl = values.Length; s < sl; s++) {
if (object.Equals(values[s].value)) {
return true;
}
}
return false;
}
For this kind of things, you may also use Linq :
using System.Linq;
...
var myArray = new float[12];
...
if(myArray.Any(a => a == 2.4))
Related
I'm trying to cut down on how much duplication I have on my code, so I decided to make one of my classes a static class since I decided that its data should really be shared with everyone. Here's the static method below:
// A static class, that holds all object's coordinates, and methods to return & update their values.
internal static class Coordinate
{
private static int[,] PlayerCoordinate { get; set; }
public static int[,] GateCoordinate { get; }
public static int[,] FountainCoordinate { get; }
static Coordinate() // FIRST VALUE IS X (column), SECOND VALUE IS Y (row).
{
PlayerCoordinate = new int[,] { { 0, 0 } };
GateCoordinate = PlayerCoordinate; // Just starts off in the same place as player.
FountainCoordinate = new int[,] { { 2, 0 } };
}
// A static method, that sends the data of all object coordinates, deconstructed into seperate ints.
public static int PlayerColumn() { return PlayerCoordinate[0, 0]; }
public static int PlayerRow() { return PlayerCoordinate[0, 1]; }
public static int GateColumn() { return GateCoordinate[0, 0]; }
public static int GateRow() { return GateCoordinate[0, 1]; }
public static int FountainColumn() { return FountainCoordinate[0, 0]; }
public static int FountainRow() { return FountainCoordinate[0, 1]; }
// Updates the coordinates of the player.
public static void UpdatePlayerCoordinate(int column, int row) { PlayerCoordinate = new int[,] { { column, row } }; }
}
The main issue comes in from my GameManager class. On the console, the beginning section should print out "You are the room at (Column=0, Row=0), but it prints this instead:
Here is the code for my GameManager class:
internal class GameManager
{
private bool IsGameOver;
private Player Player;
private Updater Updater;
// Don't need to call Fountain or Coordinate since they're static
public GameManager()
{
IsGameOver = false;
Player = new();
Updater = new();
}
public void RunGame()
{
while (!IsGameOver)
{
Console.WriteLine("----------------------------------------------------------");
Updater.DisplayPlayerPosition(); // This is the main line that I'm having issues with as of right now. All other functions past this are another problem.
Updater.DisplayPlayerSenses();
string playerInput = Player.GetInput();
Updater.MovePlayer(playerInput);
IsGameOver = Updater.CheckForWin();
}
}
}
And just to make sure, here is the code from my updater class, with the specific method that I'm having issues with:
internal class Updater
{
// No fields
// Default constructor
// Gets the text to show the player his current position.
public void DisplayPlayerPosition() // This is the method that I'm having issues with.
{
Console.WriteLine($"You are in the room at (Column={Coordinate.PlayerColumn}, Row={Coordinate.PlayerRow})");
}
...
I'm fairly new to the static keyword so I believe that I may be missing smth. I personally believe that it's because the class itself hasn't been initialized (like I haven't called the constructor for the Coordinate class, and apparently you can't call a static constructor anyways), but that's just me. If I could get any help, I'd greatly appreciate it!
PlayerColumn() and PlayerRow() are methods, but you are accesing them in the WriteLine statement as if they are properties.
Update your WriteLine to:
Console.WriteLine($"You are in the room at (Column={Coordinate.PlayerColumn()}, Row={Coordinate.PlayerRow()})");
class Program
{
static void Main(string[] args)
{
Console.Write("Your string: ");
string str = Console.ReadLine();
stringFuncs.Insert(str, "Hello", 5);
}
}
public static string SubString(string word,int a, int b)
{
for(int i = a; i < b; i++)
{
Console.Write(word[i]);//my substring method
}
return word;
}
public static string Insert(string word, string subs, int index)
{
int numberOfLetters = 0;
foreach (var c in word)
{
numberOfLetters++;
}
Console.WriteLine(stringFuncs.SubString(word, 0, index) + subs + stringFuncs.SubString(word, index,numberOfLetters-index));
return word;
}
I'm getting this as output whenever i write something : My stringHello My string
my substring method is wrong how can i make it so it only takes the part i needed and returns it back?
You can use my method (if you just need a substring method):
class Program
{
static string CustomSubstring(string text, short startIndex, short indexInQuestion)
{
short i;
for (i = startIndex; i < text.Length; i++) ;
StringBuilder Temp = new StringBuilder();
//"StringBuilder.Append()" is faster than "string+=string"
//switch is faster than if
switch (indexInQuestion < i)
{
case true:
char[] C = text.ToArray();
for (short j = startIndex; j <= indexInQuestion; j++)
{
Temp.Append(C[j]);
}
break;
}
return Temp.ToString();
}
static void Main(string[] args)
{
Console.WriteLine(CustomSubstring("Merry Christmas", 6, 14));
Console.ReadKey();
}
}
Output: Christmas
If you want a solution close to yours, with minimal changes, please consider this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp2
{
class Program
{
static void Main()
{
Console.Write("Your string: ");
string str = Console.ReadLine(); // Console should be used only in the main part, not the methods
Console.WriteLine(StringFuncs.Insert(str, "Hello", 5));
Console.ReadKey(); // Waits for the user to press a key
}
}
public class StringFuncs
{
/// <summary>
/// Extracts a part of a string
/// </summary>
/// <param name="word"></param> The string you want an extraction from
/// <param name="startIndex"></param>The position you want tthe extraction to start
/// <param name="numberOfChars"></param>The number of chars to be extracted
/// <returns></returns>
public static string SubString(string word, int startIndex, int numberOfChars)
{
string result = ""; // initialisation of the result string
for (int i = 0; i < numberOfChars; i++)
{
result += word[startIndex + i]; // adding chars one by one
}
return result;
}
// the method below was detached from your old Insert method as it can be re-used
/// <summary>
/// Calculates the number of letter of a string
/// </summary>
/// <param name="word"></param>
/// <returns></returns>
public static int NumberOfLetters(string word)
{
int numberOfLetters = 0;
foreach (char c in word) // be explicite, specific and avoid the "var" thing
{
numberOfLetters++;
}
return numberOfLetters;
}
/// <summary>
/// Inserts a string into another one, at a given position
/// </summary>
/// <param name="targetString"></param>The string which will receive the second one
/// <param name="insertString"></param>The string to be inserted in the first one
/// <param name="insertPosition"></param>The position of insertion in the first string
/// <returns></returns>
public static string Insert(string targetString, string insertString, int insertPosition)
{
return SubString(targetString, 0, insertPosition) + insertString + SubString(targetString, insertPosition, NumberOfLetters(targetString) - insertPosition);
}
}
}
It's not virtuoso-processing-and-speed argued but shows a more pedagogical approach that you can reproduce in other projects. I just prefer readability and understanding.
How can I initialize array for this generic class please help
public class MarvellousArray<T>
{
private T[] array;
public MarvellousArray(int size)
{
array = new T[size];
}
public void Accept()
{
var i = 0;
for (i = 0; i < array.Length; i++)
{
}
}
public void Display()
{
}
}
If i understand what you mean... You could do this if you need to new T
public class MarvellousArray<T>
where T : new()
{
private readonly T[] _array;
public MarvellousArray(int size)
{
_array = new T[size];
for (var i = 0; i < size; i++)
_array[i] = new T();
}
...
or just default which will be null for reference types
public class MarvellousArray<T>
{
private readonly T[] _array;
public MarvellousArray(int size)
{
_array = new T[size];
for (var i = 0; i < size; i++)
_array[i] = default(T);
}
...
If you want to initialize any array, there is the whole array Initilazier Syntax:
All possible array initialization syntaxes
The question is really what you want to Initialize it with.
The default value? ckuri pointed out that in most cases Array are initialied with that already.
A Specific value?
public static void setAll(int[] array, int value){
for(int i = 0; i<array.Lenght;i++)
array[i]=value;
}
I wrote this from memory. I am unsure if it was Size or Lenght with arrays. You could improve it with stuff like generics. Or a integer variable on how many times you want the value written.
Do you want them of a minimim size? Use List[T] and just define the minimum size with the constructor overload.
The values of another Array? List.AddRange is there for that.
Do you look for Lazy Initializsation? Then look at Lazy[T]. Alterantively you could write your class Array accessors. And initialize a empte value before you hand it out. Same way people do it with properties.
I'm writing a program , that create a random numbers and moves to an array. This is my class called randomize:
class Randomize
{
public int[] _array;
public int[] Array{ get { return _array; } set { _array= value; } }
public Randomize(int[] array)
{
Array= array;
}
public int _min;
public int Min
{
get { return _min; }
set { _min = value; }
}
public int _max;
public int Max { get { return _max; } set { _max = value; } }
public Randomize(int min, int max)
{
Min = min;
Max = max;
}
public override string ToString()
{
return string.Format(Max.ToString(), Min.ToString());
}
public override string ToString()
{
return string.Format(Array.ToString());
}
Min and Max is MinValue and MaxValue.
And now my form:
private void button1_Click(object sender, EventArgs e)
{
Randomize min = new Randomize(0, 100);
Random rand= new Random(); // randomize
Randomize[] array= new Randomize[10];
for (int i = 0; i < array.Length; i++)
{
array[i] = rand.Next(0,100); //draw in loop
}
textBox1.Clear();
for (int i = 0; i < array.Length; i++)
{
textBox1.Text = textBox1.Text + " " + array[i].ToString(); //show in textbox
}
}
And my question is how can I request my array and random numbers to my button1.
Now i have error 'cannot implicitly convert type to int' in first FOR loop.
Thanks and regards :)
Randomize[] array= new Randomize[10];
Should have been
int[] array = new int[10];
Problem
Error is in line
array[i] = rand.Next(0,100);
rand.Next(0,100); gives an integer and you cannot convert from int to Randomize. That what's error is telling.
'cannot implicitly convert type to int'
Solution
You should use an array of integer like this
int[] array= new int[10];
Wow there are some things that are problematic here. Your class should own the data, and handle its generation and display. No operations should be in the button event, other than instructing your class to display the data. Also you should have no magic numbers like 10 or 100 in the class, unless they are declared and described as a const member.
As an example look at the code below and see if you have figure out how it is different from your code (in terms of where and what is done).
public class RandomArray
{
/// <summary>
/// create a single random number generator
/// </summary>
static readonly Random generator = new Random();
/// <summary>
/// here are the random numbers stored
/// </summary>
int[] array;
/// <summary>
/// store the min, max used to generate the data
/// </summary>
readonly int min, max;
/// <summary>
/// Constructor only needs how the value limits
/// </summary>
/// <param name="min">The minimum value (typical 0)</param>
/// <param name="max">The maximum value (example 100)</param>
public RandomArray(int min, int max)
{
this.min=min;
this.max=max;
this.array=new int[0];
}
/// <summary>
/// Fills the array with random numbers
/// </summary>
/// <param name="count">The number of data to generate</param>
public void Fill(int count)
{
this.array=new int[count];
// fill array with random integers
for (int i=0; i<array.Length; i++)
{
array[i]=generator.Next(min, max);
}
}
/// <summary>
/// Copy constructor if needed (optional)
/// </summary>
/// <param name="other">A RandomArray to copy the data from</param>
public RandomArray(RandomArray other)
{
this.min=other.min;
this.max=other.max;
this.array=(int[])other.array.Clone();
}
/// <summary>
/// Provide the data
/// </summary>
public int[] Array { get { return array; } }
/// <summary>
/// Provide the limits used
/// </summary>
public int Min { get { return min; } }
public int Max { get { return max; } }
/// <summary>
/// Creates a comma separated list of numbers like <c>[45,32,64,..]</c>
/// </summary>
public string ToStringList()
{
string[] parts=new string[array.Length];
for (int i=0; i<parts.Length; i++)
{
parts[i]=array[i].ToString();
}
return "["+string.Join(",", parts)+"]";
}
/// <summary>
/// Shows only the limits used
/// </summary>
public override string ToString()
{
return string.Format("RandomArray({0},{1})", min, max);
}
}
// Click Event
private void button1_Click(object sender, EventArgs e)
{
RandomArray random_array=new RandomArray(0, 100);
random_array.Fill(10);
textBox1.Text=random_array.ToStringList();
}
public static void DoSomething()
{
int a;
string b;
//..do something
}
In the example above, i have declared two variables.
Do they become static because the method that contains them is static?
No. Only the method is static but not variables.
From MSDN:
C# does not support static local variables (variables that are declared in method scope).
if you want to have static variable in static member, do the declaration outside the static method,
private static int _var = 0;
public static void SampleMethod()
{
_var++;
}
Although available in C, static local variables are not supported in C#.
If you want a local static variable equivalent, you can create an instance variable on the class, or a static variable. Otherwise, consider if the method itself belongs to the static class and whether it should be part of a different type.
From MSDN
C# does not support static local variables (variables that are
declared in method scope).
I am positive with your opinion but in the sample code below i'am taking an access violation exception about using protected memory. Because of that maybe it isn't support static local variables but in memory management it can point same address.
public static byte[] RawSerialize(object anything)
{
int rawsize = Marshal.SizeOf(anything);
IntPtr buffer = Marshal.AllocHGlobal(rawsize);
Marshal.StructureToPtr(anything, buffer, false);
byte[] rawdata = new byte[rawsize];
Marshal.Copy(buffer, rawdata, 0, rawsize);
Marshal.FreeHGlobal(buffer);
return rawdata ;
}
You can't have local static variables.
C# does not support static local variables (variables that are declared in method scope).
No, only the method is static.
From MSDN:
C# does not support static local variables (variables that are
declared in method scope).
And here:
The static modifier can be used with classes, fields, methods,
properties, operators, events, and constructors, but it cannot be used
with indexers, destructors, or types other than classes.
As you can see, local variables are not mentioned.
You can, however use a static field:
public class MyClass
{
private static int MyVariable = 10;
public static void MyMethod()
{
MyVariable++;
}
}
A class can be static, and it can have static members, both functions and fields but not the variables in the static scope.
You can have "static" session-based variables within ASP.NET using System.Web.HttpContext.Current.Session.
Example:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace SomeNameSpace
{
public static class CSession
{
private static readonly string zE = "";
private static readonly string CrLF = Environment.NewLine;
/// <summary>
///
/// </summary>
public static bool HasSession { get { return HttpContext.Current != null && HttpContext.Current.Session != null; } }
/// <summary>
/// Get a session variable
/// </summary>
/// <param name="pSessionKey"></param>
/// <returns></returns>
public static object Get(string pSessionKey)
{
object t = null;
try
{
if (HasSession && HttpContext.Current.Session[pSessionKey] != null) { t = (object)HttpContext.Current.Session[pSessionKey]; }
}
catch (Exception ex) { t = null; string m = ex.Message; }
return t;
}//object Get(string pSessionKey)
/// <summary>
/// Set a session variable
/// </summary>
/// <param name="pSessionKey"></param>
/// <param name="pObject"></param>
public static void Set(string pSessKey, object pObject)
{
if(!HasSession) { return; }
HttpContext.Current.Session.Remove(pSessKey);
HttpContext.Current.Session.Add(pSessKey, pObject);
}//void Set(string pSessionKey, object pObject)
public static string GetString(string pSessKey)
{
string sTemp = zE;
object t = Get(pSessKey);
if (t != null) { sTemp = (string)t; } else { sTemp = zE; }
return sTemp;
}//string GetString(string pSessionKey)
public static int GetInt(string pSessKey)
{
int s = 0;
object t = Get(pSessKey);
if (t != null) { s = (int)t; }
return s;
}//int GetInt(string pSessionKey)
public static Int32 GetInt32(string pSessKey)
{
Int32 s = 0;
object t = Get(pSessKey);
if (t != null) { s = (Int32)t; }
return s;
}//Int32 GetInt32(string pSessionKey)
public static bool GetBool(string pSessKey)
{
bool s = false;
object t = Get(pSessKey);
if (t != null) { s = (bool)t; }
return s;
}//bool GetBool(string pSessionKey)
}//public static class CSession
}