I'm learning about generics, so I'm trying to make my own generic array class, which I can use to make an array of strings or an array of numeric data. This generic class has some different methods, forExample, I can add data and remove data, and search for data. All these methods works like a charm with numeric data, but I'm having some problems with making it work with strings, since it's a reference type and the default value is null, which makes my methods throw null exceptions.
My Class looks like this:
class MyArray<T> : IComparable<T>, IEnumerable<T>, IEnumerator<T>
{
T[] data = new T[10];
private int currentIndex = 0;
//This method works as intended, both with strings and ints
public void Add(T Value)
{
data[currentIndex] = Value;
currentIndex++;
if (currentIndex == data.Length)
{
T[] tmp = new T[data.Length + 10];
data.CopyTo(tmp, 0);
data = tmp;
}
}
//Can't figure out how to make this method work with strings
public void RemoveItem(T Value)
{
T[] tmp = new T[data.Length - 1];
int i = 0;
foreach (T ele in data)
{
if (!ele.Equals(Value))//This line gives me a nullRefException when I'm using strings
{
tmp[i] = ele;
i++;
}
}
data = tmp;
}
My Main form where I'm adding the data and trying to remove it looks like this:
static void Main(string[] args)
{
MyArray<string> StringArray = new MyArray<string>();
StringArray.Add("1");
StringArray.Add("2");
StringArray.RemoveItem("2");
}
I can't figure out a clever way to remove the data again, when it's a string, because of the default value of null.
Thanks in advance :)
Rather than ele.Equals(Value), use EqualityComparer<T>.Default.Equals(ele, Value); this will work correctly with null (for reference-types), Nullable<T> (for value-types), types that implement IEquatable<T>, and any other types using object.Equals.
You might want to cache it, though:
var comparer = EqualityComparer<T>.Default;
//loop
if(comparer.Equals(ele,Value)) {...}
Related
This question already has answers here:
How can I return NULL from a generic method in C#?
(13 answers)
Closed 2 years ago.
In my Data Structures class I've been tasked with creating an ArrayList of generic objects of a given type. This is essentially a class that behaves like an array with some extra functionality attached. It looks something like this.
public class GenericArray<T>
{
// The array
private T[] array;
private int size;
// Constructor
public GenericArray(int arrsize)
{
size = arrsize;
array = new T[size + 1];
}
// Array methods
public T getItem(int index)
{
return array[index];
}
public int getCount()
{
int count = 0;
for(int i = 0; i < array.Length; ++i)
{
if(array[i] != null)
count++;
}
size = count;
return count;
}
}
We're required to create the various methods by which you interact with the array. I'm having a particular problem when it comes to deleting items from the array. I have a deleteLast method which I assumed would simply set the last item to null, like so:
public void deleteLast()
{
int i = this.getCount()-1;
array[i] = null;
}
However I am getting the error that I cannot convert the parameter to null, as T may not be a nullable value type, which makes sense. However, I don't know how to remove them otherwise. I can't find any useful information on this through Google, so I've come to Stack Overflow.
Any help is appreciated. Thanks :)
Why don't you use List<T> instead of T[] ? That should easily solve all your problems!
You haven't handled cases around array size changes (for growing and reducing array size), enumeration, etc. Ideally I would implement IEnumerable and implement rest of the functions!
how can i consume this method of split List<>
private List<List<T>> SplitPartition<T>(this IEnumerable<T> collection, int size)
{
var chunks = new List<List<T>>();
var count = 0;
var temp = new List<T>();
foreach (var element in collection)
{
if (count++ == size)
{
chunks.Add(temp);
temp = new List<T>();
count = 1;
}
temp.Add(element);
}
chunks.Add(temp);
return chunks;
}
I wanna implement this list partition to my existing code:
public void ExportToCsv()
{
List<GenerateModel> members = getDataTop5000(); // I got data from my List of Data with return List<>
int offset = 0;
const int numberPerBatch = 500000; // count parameter.
double LoopMax = Math.Ceiling(members.Count / (double)numberPerBatch);
var PartitionMembers = members.SplitPartition(numberPerBatch); //error here
while (offset < LoopMax)
{
//do the index of partion here PartitionMembers
offset++;
}
}
any suggest or example how to comsume those Method? this is really what i need partition to my List. When i tried consume that method i got error like this:
List' does not contain a definition for 'SplitPartition' and no accessible extension method 'SplitPartition' accepting a first argument of type 'List' could be found (are you missing a using directive or an assembly reference?)
I think you'd be better off rolling your own solution to this. Say you had downloaded 5000 members and wanted to write them to file in 50 member chunks (100 files), you can simply do:
StringBuilder sb = new StringBuilder(10000);
int x= 0;
foreach(var m in members){
if(++x%50 == 0){
File.WriteAllText(sb.ToString(), $#"c:\temp\{x%50}.csv");
sb.Length = 0;
}
sb.AppendLine(m.ToCsvRepresentationEtc());
}
The point I'm making is not about writing to file, it's about knowing what you want to do (eg write to file) with your chunks and making a single pass of the enumerable and the cutting into chunks being done in that pass by changing what action you take every now and then. In this example changing the action is a simple modulo, that empties the buffer of the StringBuilder and writes out to a filename based on the modulo. This is preferable to burning a boatload of memory (the performance of that split routine could well be horrific depending on the numbers involved; it makes no attempt to provision any suitably sized list based on the numbers) on pre-chunking it
At the very least consider rewriting the chunking so that it uses straight 2d (jaggy) arrays or pre-capacity-provisioned lists; you know what sizes they need to be from how big the passed in List is and the chunk size:
public static class ListExtensions{
public List<List<T>> SplitPartition<T>(this IEnumerable<T> collection, int size)
{
var chunks = new List<List<T>>(collection.Count/size + 1);
var temp = new List<T>(size);
foreach (var element in collection)
{
if (temp.Count == size)
{
chunks.Add(temp);
temp = new List<T>(size);
}
temp.Add(element);
}
chunks.Add(temp);
return chunks;
}
}
Can't see your full code, but:
extension methods need to belong to static classes, and
this class and method need to be visible from the calling code.
In particular, I can see that your ExportToCsv is not static, so it doesn't belong to a static class, so I can deduce that your private extension method either:
doesn't belong to a static class, or
belongs to a separate class than your ExportToCsv method, and hence can't be seen from it
So make a public static class to hold the extension method, mark the method itself public static, and you should be in business.
More details: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/how-to-implement-and-call-a-custom-extension-method
I wanted to code a function doing something with an input object[,] and returning an object[] whose elements are object[,]'s. I just coded something stupid for a start with no input to first set up tests, and then I will properly code the function :
public static class TestData
{
public static object[,] Island1()
{
object[,] res = new object[3, 2];
res[0, 0] = 1;
res[0, 1] = 0;
res[1, 0] = 1;
res[1, 1] = 1;
res[2, 0] = 1;
res[2, 1] = 0;
return res;
}
}
public class ComponentsFinder
{
public object[] GetIslands()
{
return new object[]{TestData.Island1()};
}
}
and the test :
[TestClass]
public class TestCompomentsFinder
{
[TestMethod]
public void FirstTest()
{
object[,] island1 = TestData.Island1();
object[] expected = new object[] {island1};
object[] actual = new ComponentsFinder().GetIslands();
bool res = actual.SequenceEqual(expected);
Assert.IsTrue(res);
}
}
This test fails and I know why : even if both object[]'s contain only one object representing an object[,] that represents the same "matrix", they do not point to the same array, hence the failure of the test.
Would I have a real class C instead of object[,] it wouldn't be a problem as I would make C implement IEquatable properly, and the Equals override would then be called by SequenceEquals and the test would be ok.
But here I don't have a class, so what should I do ? Should I really wrap everything in classes or is there another way to test the equality of my object[]'s (which amounts to know to test equality of object[,]'s in the sense of having same dimensions and same respective coefficients, the coefficients of my object[,]'s are type implementing IEquatable) ?
You're correct on why SequenceEqual() fails. Arrays in C# are reference types, which means when you compare them you get reference equality, which means the CLR checks to see if they are literally the same object in memory (the two object[,]s are different objects in memory.)
In addition, SequenceEqual() is iterating through your outermost object[]'s elements, but it will not reach into those arrays's contents to iterate over the inner object[,].
You need value equality, so that you can compare the values of the objects rather than their references.
However, since you're using objects for everything, you're not going to get value equality, even if the objects are actually ints. See this example from the C# interactive window:
> object object1 = 1;
> object object2 = 1;
> object1 == object2
false
> (int)object1 == (int)object2
true
You'll need to cast the individual values back into ints before you can do a proper comparison on them. I would recommend using int arrays anyway, just for better type safety (and probably a tiny bit better performance from not performing a bunch of boxing conversions.)
All that being said, the general approach would be to iterate over every individual item and compare them individually. If they're ints in object[,] arrays, make sure to cast them ((int)) first. As for how you implement this comparison, you have several options.
You can implement your own containing class, as you've already mentioned. In that case you could override/implement interfaces to provide the functionality you need. You can also implement a standalone helper method (something like public void ArrayCompare(object[,] arr1, object[,] arr2), for instance.)
I implemented an example as an extension method, which will allow you to use either ArrayExtension.ArrayCompare(actual, expected) or actual.ArrayCompare(expected) to use it.
public static class ArrayExtension
{
public static bool ArrayCompare(this object[,] arr1, object[,] arr2)
{
if (arr1.Rank != arr2.Rank) return false;
var numDims = arr1.Rank;
for(var i = 0; i < numDims; i++)
if (arr1.GetLength(i) != arr2.GetLength(i))
return false;
for(var j = 0; j < numDims; j++)
{
var dimLength = arr1.GetLength(j);
for(var k = 0; k < dimLength; k++)
if ((int)arr1[j, k] != (int)arr2[j, k])
return false;
}
return true;
}
}
As input i have object that implements IDataRecord(row of some abstract table), so it have indexer, and by giving it some integer i can retrive object of some type. As output my code must get some range of cells in that row as array of given type objects.
So I've written this method(yes, i know, it can be easly converted to extension method, but i don't need this, and also i don't really want to have this method visible outside of my class):
private static T[] GetRange<T>(IDataRecord row, int start, int length)
{
var result = new List<T>();
for (int i = start; i < (start + length); i++)
{
result.Add((T)row[i]);
}
return result.ToArray();
}
It works fine, but this method logic seems like something very common. So, is there any method that can give same(or almost same) result in .NET Framework FCL/BCL?
Use Skip and Take.
var rangeList = result.Skip(start - 1).Take(length);
No, it is not in the BCL.
You should however not create a List<> first and then copy that to the array. Either return the List<> itself (and construct it with the appropriate initial capacity), or create the array immediately like this:
private static T[] GetRange<T>(IDataRecord row, int start, int length)
{
var result = new T[length];
for (int i = 0; i < length; i++)
{
result[i] = (T)row[start + i];
}
return result;
}
Here is an alternative (for all you LINQ lovers):
// NB! Lazy enumeration
private static IEnumerable<T> GetRange<T>(IDataRecord row, int start, int length)
{
return Enumerable.Range(start, length).Select(i => (T)row[i]);
}
We repeat here what was stated in the comments to the question: The interface System.Data.IDataRecord (in System.Data.dll assembly) does not inherit IEnumerable<> or IEnumerable.
If you want to 'TakeARange' you should have a collection as input parameter.
Here you don't have one.
You just have a IDataRecord (eg. a single row) that has an indexer.
You should expose a property called Cells that return the list you work with in the indexer implementation.
Your method should look like this:
private static T[] TakeRange<T>(IEnumerable cells, int start, int length)
{
return cells.Skip(start - 1).Take(length)
}
Well.. Seem's like there is no such method in FCL/BCL
My program intensively uses Reverse, e.g. Array.Reverse(myArray,3,5)
I would like my program could accept both array and List as input, so I go for IList
However, I couldn't find an IList method which is the same as Reverse.
There is one extension method named Reverse, however it produces IEnumerable stream but not in-place rearrangement. (which I assume takes more copy time)
I thought of using cast, but was afraid that cast would be inefficient as well.
So, what should I do?
Worst case scenario, I make 2 program, 1 takes array, the other takes List, and then overloading?
OOP-way - make a wrapper, overload it dozen times:
public void Reverse(Array arr, int index, int count)
{
Array.Reverse(arr, index, count);
}
public void Reverse<T>(List<T> lst, int index, int count)
{
lst.Reverse(index, count);
}
Add an overload each time you need another collection-alike class to be reversed in such way. This approach relies on system internals, very effective and robust, but may be verbose in case you are willing to reverse many kinds of objects.
I-can-do-it-myself-better-way:
static class Extensions
{
public static void Reverse(this IList target, int index, int count)
{
int right = index + count - 1;
int left = index;
while (right>left)
{
var tmp = target[left];
target[left] = target[right];
target[right] = tmp;
right--;
left++;
}
}
}
Just add range checks/preconditions/invariants/etc. Also, it might be inefficient with lists, as it requires random access to the contents of the list, but I think you can't workaround it using "conventional weapons" (i.e. not using reflection and direct memory manipulation).
So, my suggestion - overloading is the way to go.
The Linq Reverse() extension method misses an obvious optimization, it always creates a temporary array to store elements to reverse them. This is too expensive to use on a list or array.
If you want an in-place reverse then you could write an extension method that selects the proper Reverse() method:
public static class MyExtensions {
public static void Reverse<T>(this IList<T> source) {
if (source is List<T>) {
((List<T>)source).Reverse();
}
else if (source is T[]) {
Array.Reverse((T[])source);
}
else throw new ArgumentException();
}
}
You can fix the Linq Reverse method the same way:
public static class MyExtensions {
public static IEnumerable<T> Reverse<T>(this IEnumerable<T> source) {
if (source is IList<T>) {
var list = (IList<T>)source;
for (int ix = list.Count - 1; ix >= 0; --ix) {
yield return list[ix];
}
}
else {
foreach (var item in Enumerable.Reverse(source)) {
yield return item;
}
}
}
}
Reverse() will produce an IEnumerable directly based off the list; no copying involved. Give it a try, it may be more efficient if you're only iterating.
Array.Reverse() is static:
T[] arr = ...
Array.Reverse(arr); // in-place
List.Reverse is not :
List<T> list = ...
list.Reverse(); // in-place too
Also there is a LINQ extension method:
IList<T> ilist = ...
IEnumerable<T> e = ilist.AsEnumerable();
IEnumerable<T> result = e.Reverse(); // not in-place
If you want an in-place Reverse method that takes an IList, rather than just a List or an Array, you'll have to write it yourself. It's not a particularly complex algorithm, so I imagine you're capable of writing such a method yourself.