Primitives and IComparable interface - c#

In Java if I wanna sort any data independent to its data type I would use Comparable interface and I found out we have similar interface in C#, so I have simple sorting algorithm:
public static void Sort(IComparable[] arr)
{
bool swap = true;
while (swap)
{
swap = false;
for (int i = 0; i < arr.Length - 1; i++)
{
if (Less(arr[i + 1], arr[i]))
{
Exchange(arr, i, i + 1);
swap = true;
}
}
}
}
So I can sort any objects that implements IComparable interface, but I can't sort any primitive datatypes and as I know C# doesn't have wrapper types for primitives like int -> Integer, but it has some structures like Int32 that actually implements IComparable interface but I still can't use it for some reason, for example:
static void Main(string[] args)
{
Int32[] ints = { 5, 2, 9, 0, 3};
BubbleSort.Sort(ints);
ReadKey();
}
I will get an error:
Error CS1503 Argument 1: cannot convert from 'int[]' to 'System.IComparable[]'
But if we check out metadata of Int32 we can see it implements IComparable
So,
What I don't know?
What's wrong here?
How can I make it better to sort any data?

An int[] isn't an IComparable[] - the latter is an array of references.
But there's a simple solution, which will also avoid boxing. Change your method declaration to be generic with a constraint on the type parameter:
public static void Sort<T>(IComparable<T>[] arr) where T : IComparable<T>
You may need to change your Exchange and Less methods as well - you haven't told us what that looks like. But they could (and probably should) be generic too. The method body of Sort shouldn't need to change, at that point.

If someone was interested:
public static class BubbleSort<T>
{
public static void Sort(T[] arr, Comparer<T> comparer = null)
{
Comparer<T> equaltyComparer = comparer ?? Comparer<T>.Default;
bool swap = true;
while (swap)
{
swap = false;
for (int i = 0; i < arr.Length - 1; i++)
{
if (Less(equaltyComparer, arr[i + 1], arr[i]))
{
Exchange(arr, i, i + 1);
swap = true;
}
}
}
}
private static bool Less(Comparer<T> comparer, T v, T w)
{
return comparer.Compare(v, w) < 0;
}
private static void Exchange(T[] arr, int i, int j)
{
T temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}

Related

c# extension methods for generic array

I'm trying to make extension methods for generic array, so I could takeout random set of elements.
I made following extension methods for List<T> type and they work great, but I can't work out how to do exactly the same for generic array:
public static T Random<T>(this List<T> list)
{
return list[GameManager.instance.functions.RandomInt(list.Count - 1)];
}
public static IEquatable Random<IEquatable>(this List<IEquatable> list, List<IEquatable> hits)
{
int rand = GameManager.instance.functions.RandomInt(list.Count - 1);
while (hits.Exists(h => h.Equals(list[rand])))
rand = GameManager.instance.functions.RandomInt(list.Count - 1);
return list[rand];
}
public static List<T> Random<T>(this List<T> list, int count)
{
List<T> result = new List<T>();
for (int i = 0; i < count; i++)
{
result.Add(list.Random());
}
return result;
}
public static List<IEquatable> RandomUnique<IEquatable>(this List<IEquatable> list, int count)
{
List<IEquatable> result = new List<IEquatable>();
for (int i = 0; i < count; i++)
{
result.Add(list.Random(result));
}
return result;
}
I tried to rework the first method like this:
public static IEnumerable Random<IEnumerable>(this IEnumerable list)
but it doesn't recognize list as an array so I can't get to it's length value.
I see a workaround, to do a List from Array, then get my random values and make array again, but it's seems like too much action for just taking eg. 2 random from 4 elements array.
Please advise
EDIT:
Thanks to Mathew in comments, I managed to construct the extension method for generic array correctly:
public static T Random<T>(this T[] list)
{
return list[GameManager.instance.functions.RandomInt(list.Length - 1)];
}
But ultimately I'll play around with the Dmitry's answer and try to make these for IEnumerable. Thank you very much!
EDIT2:
Thanks to Zastai, I changed all methods so they work for both List and generic array:
public static T Random<T>(this IReadOnlyList<T> list)
{
return list[GameManager.instance.functions.RandomInt(list.Count - 1)];
}
public static IEquatable Random<IEquatable>(this IReadOnlyList<IEquatable> list, List<IEquatable> hits)
{
int rand = GameManager.instance.functions.RandomInt(list.Count - 1);
while (hits.Exists(h => h.Equals(list[rand])))
rand = GameManager.instance.functions.RandomInt(list.Count - 1);
return list[rand];
}
public static List<T> Random<T>(this IReadOnlyList<T> list, int count)
{
List<T> result = new();
for (int i = 0; i < count; i++)
{
result.Add(list.Random());
}
return result;
}
public static List<IEquatable> RandomUnique<IEquatable>(this IReadOnlyList<IEquatable> list, int count)
{
List<IEquatable> result = new();
for (int i = 0; i < count; i++)
{
result.Add(list.Random(result));
}
return result;
}
Doesn't work for strings (as in "abcdefg".Random()), but for my needs it's not neccessary.
IEnumerable is specifically just a sequence of values, and has no length.
IReadOnlyList on the other hand, is a list of values (so does have a length) and does not allow adding/removing values.
A .NET array implements both.
So if you change your extension methods to take IReadOnlyList<xxx> instead of List<xxx> they should automatically work on arrays too.
Instead of implementing extensions methods for List<T>, T[] etc. you can try implementing a
single routine for IEnumerable<T>, e.g.
public static partial class EnumerableExtensions {
public static T Random<T>(this IEnumerable<T> source) {
//DONE: do not forget to validate public methods' arguments
if (source is null)
throw new ArgumentNullException(nameof(source));
// If enumerable is a collection (array, list) we can address items explictitly
if (source is ICollection<T> collection) {
if (collection.Count <= 0)
throw new ArgumentOutOfRangeException(nameof(source),
$"Empty {nameof(source)} is not supported.");
return collection[GameManager.instance.functions.RandomInt(collection.Count - 1)];
}
// In general case we have to materialize the enumeration
var list = source.ToList();
if (list.Count <= 0)
throw new ArgumentOutOfRangeException(nameof(source),
$"Empty {nameof(source)} is not supported.");
return list[GameManager.instance.functions.RandomInt(list.Count - 1)];
}
}
Then you can use the same extension method with list, array etc.:
// Array
int demo1 = new int[] {4, 5, 6}.Random();
// List
double demo2 = new List<double>() {1.0. 3.0}.Random();
// String is not array or list but implements IEnumerable<char>
char demo3 = "abcdef".Random();
As an alternative to consider: You can use Reservoir sampling to select N items from a sequence of unknown length.
Here's a sample implementation:
/// <summary>Randomly selects n elements from a sequence of items.</summary>
public static List<T> RandomlySelectedItems<T>(IEnumerable<T> items, int n, System.Random rng)
{
// See http://en.wikipedia.org/wiki/Reservoir_sampling for details.
var result = new List<T>(n);
int index = 0;
foreach (var item in items)
{
if (index < n)
{
result.Add(item);
}
else
{
int r = rng.Next(0, index + 1);
if (r < n)
result[r] = item;
}
++index;
}
if (index < n)
throw new ArgumentException("Input sequence too short");
return result;
}

Non-0 based arrays in C# with traditional [ ] array syntax?

I'd like to be able to create an array in C# with an arbitrary range of index bounds, e.g., a 16 element array with indices of 100-115.
Native arrays in C# are 0-based, but I'm told (e.g., in Luaan's comment here), that the C# Array class allows arbitrary lower and upper bounds. But in the examples I've seen elements in the Array class are accessed via myArray.GetValue() and myArray.SetValue() instead of conventional array syntax like myArray [ foo ].
Array arr = Array.CreateInstance(typeof(string), new[]{16}, new[]{100});
Console.WriteLine(arr.Length); // 16
arr.SetValue("foo", 100);
Console.WriteLine(arr.GetValue(100)); // foo
Is there any way to make an array with some arbitrary starting index, like [100] that I can access with traditional [ ] syntax in C#?
You could create a class that implements the decorator pattern: just implement the IList interface (wich is also implemented by Array) and do whatever shifting you want on the this [int index] property.
The decorator pattern is described here:
http://www.codeproject.com/Articles/479635/UnderstandingplusandplusImplementingplusDecoratorp
The Array class does not support this, but you can write your own array class with one-based indices:
public class OneBasedArray<T>
{
public T[] InnerArray;
public T this[int i]
{
get { return InnerArray[i-1]; }
set { InnerArray[i-1] = value; }
}
}
And then use it like this:
var myArray = new OneBasedArray<int> { InnerArray = new int[]{ 1, 2, 3, 4, 5 } };
for(int i = 1; i <=5; i++)
{
Console.WriteLine(myArray[i]);
}
This code is only to get the idea, such a class would of course need a nicer interface.
You can only use an array's indexer when it's a 0-indexed array.
You can use an indexer for a custom, non-array, type, and use whatever logic you want for it, such as making it non-zero-indexed, but that's not an option for arrays.
I think Lukas' answer is probably the easiest way to handle this, but if, for some reason, you really wanted to use Array.CreateInstance (not sure why you would - maybe some external library might insist on it?), you could wrap it in a class like this:
public class NonZeroArray<T>
{
private readonly Array array;
public T this[int i]
{
get { return (T)array.GetValue(i); }
set { array.SetValue(value, i); }
}
public NonZeroArray(int length, int lowerBounds = 0)
{
array = Array.CreateInstance(typeof(T), new int[] { length}, new int[] { lowerBounds } );
}
}
You could obviously make this a lot prettier (and easier to work with) by having it implement the rest of IList<T>. And if you really need the native array, you could implement a property with a getter to expose it when needed.
Using it would be simply:
var myNonZeroArray = new NonZeroArray<string>(16,100);
myNonZeroArray[100] = "foo";
Console.WriteLine(myNonZeroArray[100]); // prints "foo"
Here's a custom class that extends IList<T> to provide functionality for starting at a non-zero index:
public class NonZeroList<T> : IList<T>
{
private int startIndex;
private List<T> inner;
public NonZeroList(int startIndex, IEnumerable<T> content)
{
this.startIndex = startIndex;
inner = content.ToList();
}
public NonZeroList(int startIndex)
{
this.startIndex = startIndex;
inner = new List<T>();
}
public T this[int i]
{
get
{
return inner[i - startIndex];
}
set
{
inner[i - startIndex] = value;
}
}
public IEnumerator<T> GetEnumerator()
{
foreach (T i in inner)
yield return i;
yield break;
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return inner.GetEnumerator();
}
public int IndexOf(T item)
{
return inner.IndexOf(item) + startIndex;
}
public void Insert(int index, T item)
{
inner.Insert(index - startIndex, item);
}
public void RemoveAt(int index)
{
inner.RemoveAt(index - startIndex);
}
public void Add(T item)
{
inner.Add(item);
}
public void Clear()
{
inner.Clear();
}
public bool Contains(T item)
{
return inner.Contains(item);
}
public void CopyTo(T[] array, int arrayIndex)
{
inner.CopyTo(array, arrayIndex);
}
public int Count
{
get { return inner.Count; }
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(T item)
{
return inner.Remove(item);
}
}
To use it, you initialize it just as you would a normal List<T>, but with the start index specified (e.g. NonZeroList<int> myList = new NonZeroList<int>(20) { 0, 1, 2, 3 };). You can then use it just as you would a normal List<T> or T[].
If you want to use it as an array instead of a list, then you can simply add bounds checking or implement IEnumerable<T> instead of IList<T>, and create utility functions yourself.

C# Working with a generic list in a method

I have been teaching myself generics and I wanted to try it out with a list but I struggled upon a problem I cant figure out how to "feed" the generic list to my method. What is the proper way to make a generic method "eat" my list? :)
Heres my code:
class Program<AnyDataType>
{
static void Main(string[] args)
{
jdtlist.Add("something");
jdtlist.Add("something");
jdtlist.Add("something");
Console.WriteLine(countlist(jdtlist));
Console.ReadKey();
}
static List<AnyDataType> jdtlist = new List<AnyDataType>();
public static int countlist(List<AnyDataType> list) // Yes I know this is practically useless but thats not why I am here :)
{
int listcount = 0;
for (int i = 0; i < list.Count; i++)
{
listcount++;
}
return listcount;
}
If you are writing generic method, then it should have generic parameter
public static int CountList<T>(List<T> list)
{
int listcount = 0;
for (int i = 0; i < list.Count; i++)
listcount++;
return listcount;
}
Then you can call it with any generic list
var list = new List<AnyDataType>();
// ..
Foo.CountList(list);
Same goes to classes. If you want to parametrize class with some generic type, you should provide generic argument
public class Foo<T>
As #DStanley stated, you don't need to parametrize individual methods in that case
public class Foo<T>
{
public static int CountList(List<T> list)
{
int listcount = 0;
for (int i = 0; i < list.Count; i++)
listcount++;
return listcount;
}
}
But you need to parametrize class
Foo<int>.CountList(list)
Suggested reading: Generics (C# Programming Guide)
Your problem is not passing the list to your method - that part is fine. Your problem is that you're trying to fill a "generic" list with a "specific" type (namely strings). Making a class generic means "I am not specifying the data type here - the consumer of the class will do that". So a better use case for your class would be:
class Program
{
static void Main(string[] args)
{
MyList<string>.Add("something");
MyList<string>.Add("something");
MyList<string>.Add("something");
Console.WriteLine(MyList<string>.countlist(MyList<string>.jdtlist));
Console.ReadKey();
}
}
public class MyList<AnyDataType>
{
public static List<AnyDataType> jdtlist = new List<AnyDataType>();
public static void Add(AnyDataType item)
{
jdtList.Add(item);
}
public static int countlist(List<AnyDataType> list)
{
int listcount = 0;
for (int i = 0; i < list.Count; i++)
{
listcount++;
}
return listcount;
}
This is the minimum needed to get your program to work - there are several improvements that can be made (not using static so much, etc.) but hopefully it helps you understand generics better.
You need to call the static method of the generic class via class-name including the type of the parameter:
so instead of
Console.WriteLine(countlist(jdtlist));
this:
Console.WriteLine(Program<string>.countlist(jdtlist));
Another way is to make the method generic, not the class:
public static int countlist<AnyDataType>(List<AnyDataType> list) {}
Then you can call it in these ways(with explicit type or inferred from parameter):
Program1.countlist<string>(jdtlist)
Program1.countlist(jdtlist)
Okay you have:
public static int countlist(List<AnyDataType> list)
{
int listcount = 0;
for (int i = 0; i < list.Count; i++)
{
listcount++;
}
return listcount;
}
And well, it works fine, but only if you have List<AnyDataType> to begin with.
Well, you could do:
public static int Countlist<T>(List<T> list)
{
int listcount = 0;
for (int i = 0; i < list.Count; i++)
{
listcount++;
}
return listcount;
}
Now the method itself is generic. What's more overloads will happen automatically in that you can call CountList(new List<string>()) rather than having to explicitly call CountList<strong>(new List<string>()).
But this combines with simple matters of inheritance. Consider that your CountList could work just as well with any other IEnumerable<T> implementation:
public static int Count<T>(IEnumerable<T> source)
{
int tally = 0;
foreach(var item in source)
++tally;
return tally;
}
So just as generics mean you don't have to restrict yourself to a particular type of list, so normal inheritance and interface implementation means you can work with the most general case applicable.

Dictionary<int [], bool> - compare values in the array, not reference?

I am using dictionary for storing ID,otherID and bool value. Unfortunately it compares array reference, therefore I cannot use it.
Is there any way how to have an array as key but compare its values instead of reference?
Thanks
You can use the Comparer property of the dictionary to set it to a custom comparer created by you.
EDIT: actually the property is read-only, sorry. You should definitely use the proper constructor:
class IntArrayComparer : IEqualityComparer<int[]> {
public bool Equals(int[] x, int[] y) {
if (x.Length != y.Length) {
return false;
}
for (int i = 0; i < x.Length; ++i) {
if (x[i] != y[i]) {
return false;
}
}
return true;
}
public int GetHashCode(int[] obj) {
int ret = 0;
for (int i = 0; i < obj.Length; ++i) {
ret ^= obj[i].GetHashCode();
}
return ret;
}
}
static void Main(string[] args) {
Dictionary<int[], bool> dict = new Dictionary<int[], bool>(new IntArrayComparer());
}
You can try implementing IEqualityComparer<int[]> and then pass an instance of it to the proper constructor.
There are basically two ways of doing that:
Create a comparer that implements IEqualityComparable<int[]>, that you pass to the constructor of the dictionary.
Create a key class that encapsulates the integer array and implements IEquatable<T>.
There's nothing wrong with orsogufo's answer, but I wanted to point out that if you have .NET 3.5, you can implement an ArrayValueComparer with a lot less code, and at the same time make it generic, so it can compare the values of any type of array, and not just integer arrays. For that matter, you could easily make it work with any IEnumerable, and not just arrays.
using System.Collections.Generic;
using System.Linq;
class ArrayValueComparer<T> : IEqualityComparer<T[]>
{
public bool Equals(T[] x, T[] y)
{
return x.SequenceEqual(y, EqualityComparer<T>.Default);
}
public int GetHashCode(T[] obj)
{
return obj.Aggregate(0, (total, next) => total ^ next.GetHashCode());
}
}
static void Main(string[] args)
{
var dict = new Dictionary<int[], bool>(new ArrayValueComparer<int>());
}

How to specify parameter for generic list type extension method in c#

I am trying to make an extension method that will shuffle the contents of a generic list collection regardless of its type however im not sure what to put in between the <..> as the parameter. do i put object? or Type? I would like to be able to use this on any List collection i have.
Thanks!
public static void Shuffle(this List<???????> source)
{
Random rnd = new Random();
for (int i = 0; i < source.Count; i++)
{
int index = rnd.Next(0, source.Count);
object o = source[0];
source.RemoveAt(0);
source.Insert(index, o);
}
}
You need to make it a generic method:
public static void Shuffle<T>(this List<T> source)
{
Random rnd = new Random();
for (int i = 0; i < source.Count; i++)
{
int index = rnd.Next(0, source.Count);
T o = source[0];
source.RemoveAt(0);
source.Insert(index, o);
}
}
That will allow it to work with any List<T>.
You just make your own method generic:
public static void Shuffle<T>(this List<T> source)
Slightly off-topic, but a Fisher-Yates shuffle will have less bias and better performance than your method:
public static void ShuffleInPlace<T>(this IList<T> source)
{
if (source == null) throw new ArgumentNullException("source");
var rng = new Random();
for (int i = 0; i < source.Count - 1; i++)
{
int j = rng.Next(i, source.Count);
T temp = source[j];
source[j] = source[i];
source[i] = temp;
}
}
I Think this solution faster to process, because you will get your itens randomly and your collection position will be preserved to future use.
namespace MyNamespace
{
public static class MyExtensions
{
public static T GetRandom<T>(this List<T> source)
{
Random rnd = new Random();
int index = rnd.Next(0, source.Count);
T o = source[index];
return o;
}
}
}
Steps:
Create your Static Class to Identify your extensions
Create you Extension Method (must be static)
Process your data.

Categories

Resources