Can you write a swap routine for generic lists covariantly? Here is a swap routine which won't work:
public static void Swap(List<IComparable> list, int pos1, int pos2)
{
IComparable temp = list[pos1];
list[pos1] = list[pos2];
list[pos2] = temp;
}
Calling Swap(new List<int>{1,2}, 0, 1) won't work here because this version of Swap isn't covariant.
Does this work for you?
public static void Swap<T>(this List<T> list, int pos1, int pos2)
{
T tmp = list[pos1];
list[pos1] = list[pos2];
list[pos2] = tmp;
}
This allows you to specify the type and make the swap possible.
Related
I want to ensure that my List can contain only 2 elements array of int. I am currently have to declare a struct but I really don't want to declare many type if it is not really necessary. So I am wondering if I can declare a list of fixed size array.
static void Main(string[] args)
{
//I want to declare something like this
List<int[2]> list = new List<int[2]>();
list.Add(new int[2] { 1, 2 });
list.Add(new int[2] { 3, 4 });
//What I having to do(not really want because I have to declare struct)
List<TwoElement> list2 = new List<TwoElement>();
list2.Add(new TwoElement() { Element1 = 1, Element2 = 2 });
list2.Add(new TwoElement() { Element1 = 1, Element2 = 2 });
}
private struct TwoElement
{
public int Element1;
public int Element2;
}
It's not possible, as reference from this post, in short, int[2] is not a Type, therefore no way to limit it without a struct, model or tuple.
I will prefer using tuple in this case, since it's pretty simple with lambda
List<(int, int)> list = new List<(int, int)>();
list.Add((1, 1));
list.Add((2, 3));
Here's an idea of a fixed length array. If the length was more than 2, then I'd probably have a private int[] theArray member. But, at two, it probably makes sense to have a _first and a _second member the way I show. The System.Array class has a lot of members - you get to implement the ones you care about (I put all the Properties in (either as a property or as a const)).
In any case, it gives you an idea of a possible solution:
public class ArrayOf2Int : IEnumerable<int>
{
private readonly int _first;
private readonly int _second;
//I had the urge to make this a Lazy<object> - but it's an object, who cares
//If you implement this with an array of int (int[]) instead of two ints, delegate this to the SyncRoot of the array
public object SyncRoot { get; } = new object();
public const int Length = 2;
public const long LongLength = 2;
public const int Rank = 1;
public const bool IsFixedSize = true;
public const bool IsSynchronized = false;
public ArrayOf2Int(int first, int second)
{
_first = first;
_second = second;
}
public int this[int i]
{
get
{
if (i < 0 || i > 1)
{
throw new ArgumentOutOfRangeException(nameof(i), "Index out of range");
}
return i == 0 ? _first : _second;
}
}
public IEnumerator<int> GetEnumerator()
{
yield return _first;
yield return _second;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
I have two classes
class CSparseMatrix:
{
public int NumberOfDimensions { get; set;}
public int DefaultNumber { get; set; }
List<int> dimensionsRanges = new List<int>(); // that's specify dimension of ranges, f.e. {100, 100, 100, 120..}
List<CSparseCell> cells = new List<CSparseCell>(); // contains only values different from default for this matrix
}
class CSparseCell {
public int Value { get; set; }
public List<int> coordinates = new List<int>();
}
And the problem is: how to loop through this CSparseMatrix and output all ranges with values in format like: [0, 0, 0, 0] - *value*, [0, 0, 0, 1] - *value*, [0, 0, 0, 2] - *value*, ...[dimensionsRanges[0]-1, dimensionsRanges[1]-1, dimensionsRanges[2]-1, dimensionsRanges[3]-1] - *value* so through all ranges and output all values (we can have any number of this dimensions).
That means that in program we had to to output all values of matrix, which can have any number of dimensions and ranges could be different. But we don't know what this number of dimensions will be so can't use n-nested loops, and actually I have no idea of algorithm or method how to iterate through all values from List<int> dimensionsRanges
The way, we get the specific value from this "matrix" is
public int GetValueFromCell(List<int> coordinate)
{
foreach(CSparseCell cell in cells)
{
if(cell.coordinates.All(coordinate.Contains)) {
return cell.Value;
}
}
return DefaultNumber;
}
Since you say your matrix is large, avoid returning CSparseCell by pushing the Value lookup to the answer computation.
You create a method to return all the coordinates in the sparse matrix, using a helper method to increment coordinates. NOTE: I changed the coordinate increment method to use a for loop instead of do which might be easier to understand (?).
void IncCoord(ref List<int> aCoord) { // ref not needed, just for documentation
for (var curDim = NumberOfDimensions - 1; curDim >= 0; --curDim) {
if (aCoord[curDim] == dimensionsRanges[curDim] - 1) // handle carry
aCoord[curDim] = 0;
else {
++aCoord[curDim];
break;
}
}
}
public IEnumerable<List<int>> AllCoords() {
var curCellCoord = Enumerable.Repeat(0, NumberOfDimensions).ToList();
var numCells = dimensionsRanges.Product();
for (int j1 = 0; j1 < numCells; ++j1) {
yield return curCellCoord.ToList();
IncCoord(ref curCellCoord);
}
}
Now you can use this method to get all Values and you can format the output however you like. Assuming t is a CSparseMatrix:
var ans = t.AllCoords().Select(c => $"[{c.Join(",")}] - {t.GetValueFromCell(c)}");
A couple of helper extension methods are used:
public static class IEnumerableExt {
public static int Product(this IEnumerable<int> src) => src.Aggregate(1, (a,n) => a * n);
}
public static class StringExt {
public static string Join<T>(this IEnumerable<T> items, string sep) => String.Join(sep, items);
}
I'd make a couple suggestions. First tying the coordinate and the value together complicate things. It'd be much better to separate those two.
Secondly, having to search the entire array to find a single cell makes it very inefficient. You can create a simple sparse matrix out of a dictionary. This not at all the best way but with the unknown key requirements you have given it's at least better than the array. (is it really a matrix if the key is 1..n ?)
Here's an example. First we make the coordinates their own type.
readonly struct SparseCoord : IEquatable<SparseCoord>
{
public static SparseCoord ToCoordinate(params int[] coords)
{
return new SparseCoord(coords);
}
public SparseCoord(int[] c)
{
this.Coordinate = new int[c?.Length ?? 0];
if (null != c)
c.CopyTo(this.Coordinate, 0);
}
public int[] Coordinate { get; }
public bool Equals([AllowNull] SparseCoord other)
{
return Enumerable.SequenceEqual(this.Coordinate, other.Coordinate);
}
public override bool Equals(object obj)
{
if (obj is SparseCoord c)
return this.Equals(c);
return false;
}
public override int GetHashCode()
{
var hash = new HashCode();
foreach (var i in this.Coordinate)
hash.Add(i);
return hash.ToHashCode();
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.Append('(');
foreach (var i in this.Coordinate)
{
sb.Append(i);
sb.Append(',');
}
sb.Length = sb.Length - 1;
sb.Append(')');
return sb.ToString();
}
}
Then we create a sparse matrix using a dictionary as the storage. Note this is incomplete obviously as there's no way to clear it partially or completely but again it's just an example.
class SparseMatrix : IEnumerable<KeyValuePair<SparseCoord, int>>
{
Dictionary<SparseCoord, int> cells = new Dictionary<SparseCoord, int>();
public int this[SparseCoord coord]
{
get
{
if (this.cells.TryGetValue(coord, out var ret))
return ret;
return 0;
}
set
{
this.cells[coord] = value;
}
}
public IEnumerator<KeyValuePair<SparseCoord, int>> GetEnumerator()
{
return this.cells.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
Then you can add values and iterate over the contents:
static void Main(string[] _)
{
SparseMatrix matrix = new SparseMatrix();
matrix[SparseCoord.ToCoordinate(1, 2, 3)] = 1;
matrix[SparseCoord.ToCoordinate(5, 6, 7)] = 2;
foreach (var value in matrix)
Console.WriteLine(value);
}
Finally I would reiterate that if your matrix really is going to get "big" as you said in a comment then you should invest some time in looking at some well known implementations of sparse matrix.
I created the pair class and array class, but I'm lost on how to implement the quicksort algorithm.
I want to do it if ints are same then I should sort by double. I was able to implement quicksort with one value per index of array, but with this I just can't find any resources.
Maybe you guys have some resources or maybe you had the same problem?
By the way I'm trying to implement it with c#.
This is my pair class:
class Pair
{
public int integer = 0;
public double doubl = 0.0;
public Pair(int integer, double doubl)
{
this.integer = integer;
this.doubl = doubl;
}
public Pair()
{
}
public int Integer() { return integer; }
public double Doubl() { return doubl; }
}
And my data array class
class MyDataArray : DataArray
{
Pair[] data;
int operations = 0;
public MyDataArray(int n, int seed)
{
data = new Pair[n];
Random rand = new Random(seed);
for (int i = 0; i < n; i++)
{
data[i] = new Pair(rand.Next(1,100), rand.NextDouble());
}
}
public override int integer(int index)
{
return data[index].integer;
}
public override double doubl(int index)
{
return data[index].doubl;
}
public override void Swap(int i, int j)
{
Pair temp = data[i]; // c3 1
data[i] = data[j]; // c3 1
data[j] = temp; // c3 1
}
Your Pair class could implement IComparable<T>, and your quick sort algorithm could be implemented using the CompareTo method.
The IComparable<T> interface:
Defines a generalized comparison method that a value type or class implements to create a type-specific comparison method for ordering or sorting its instances.
You can see the documentation on the CompareTo method to see what the return values mean.
public class Pair : IComparable<Pair>
{
public int integer = 0;
public double doubl = 0.0;
public Pair(int integer, double doubl)
{
this.integer = integer;
this.doubl = doubl;
}
public Pair()
{
}
public int CompareTo(Pair other)
{
if (other == null)
{
return 1;
}
int result = integer.CompareTo(other.integer);
if (result == 0)
{
result = doubl.CompareTo(other.doubl);
}
return result;
}
public int Integer() { return integer; }
public double Doubl() { return doubl; }
}
If you prefer to use the comparison operators, you can implement them in terms of the CompareTo method. The documentation I liked has examples on how to do that.
//sort for integer
var SortedIntegerList = data.OrderBy(x=>x.integer);
//sort for double
var SortedDoubleList = data.OrderBy(x=>x.doubl);
OrderBy for objects uses Quicksort - What Sorting Algorithm Is Used By LINQ "OrderBy"? - so you can use that.
To avoid creating IComparer<Pair> interface you can construct it using Comparer<T>.Create from just comparison delegate:
var sorted = source.OrderBy(x => x, Comparer<Pair>.Create(
(p1, p2) => p1.Integer() - p2.Integer() != 0 ?
p1.Integer() - p2.Integer() :
Math.Sign(p1.Doubl() - p2.Doubl()))).ToList();
I am learning basic sort algorithms from some source in github. Now, I am trying to make a method that can be used for all sorter instance but I am facing error CS1503 which says that I can not convert int[] into T[]. The intellisense recommends me to add new method but I don't want to add it. Here is my code:
class Program
{
static void Main(string[] args)
{
test<int>(new BubbleSorter<int>(), new IntComparer());
}
static void test<T>(ISorter<T> sorter, IComparer<T> intComparer)
{
var (correctArray, testArray) = RandomHelper.GetArrays(10); //Generates random arrays
sorter.Sort(testArray, intComparer); //This line error
Array.Sort(correctArray);
Console.WriteLine(string.Join(",", testArray));
Console.WriteLine(string.Join(",", correctArray));
}
}
public interface ISorter<T>
{
void Sort(T[] array, IComparer<T> comparer);
}
class BubbleSorter<T> : ISorter<T>
{
public void Sort(T[] array, IComparer<T> comparer) {//Sort}
}
internal class IntComparer : IComparer<int>
{
public int Compare(int x, int y)
{
return x.CompareTo(y);
}
}
internal static class RandomHelper
{
public static (int[] testArray, int[] correctArray) GetArrays(int n)
{
int[] testArr = new int[n];
int[] correctArr = new int[n];
Random rnd = new Random();
for (int i = 0; i < n; i++)
{
int t = rnd.Next(1, 1000);
testArr[i] = t;
correctArr[i] = t;
}
return (testArr, correctArr);
}
}
What I want to achieve that I want to do this with one test method:
static void Main(string[] args)
{
test<int>(new BubbleSorter<int>(), new IntComparer());
test<int>(new SelectionSorter<int>(), new IntComparer());
test<int>(new MergeSorter<int>(), new IntComparer());
}
test is supposed to be able to work on any T, right? But RandomHelper.GetArrays can only return int[]! To make your test method able to test any T, you need to write a GetArrays method that can generate test cases for any T as well, not just for int.
So now you have two choices:
Make test non-generic because you only need to sort ints here.
Make GetArrays work on any T.
For option 1, you can just remove all the <T> and replace T with int, like this:
class Program
{
static void Main(string[] args)
{
test(new BubbleSorter(), new IntComparer());
}
static void test(ISorter sorter, IComparer<int> intComparer)
{
var (correctArray, testArray) = RandomHelper.GetArrays(10);
sorter.Sort(testArray, intComparer);
// Array.Sort(correctArray); // you should do this in GetArrays instead! You should also pass intComparer to Array.Sort as well!
Console.WriteLine(string.Join(",", testArray));
Console.WriteLine(string.Join(",", correctArray));
}
}
public interface ISorter
{
void Sort(int[] array, IComparer<int> comparer);
}
class BubbleSorter : ISorter
{
public void Sort(int[] array, IComparer<int> comparer) {//Sort}
}
One way to do option 2 is to add a Func<int, T> parameter to GetArrays telling it how to transform an int to a T. You would also need a IComparer<T> parameter to sort the correct array as I mentioned above,
public static (T[] testArray, T[] correctArray) GetArrays<T>(int n, Func<int, T> transform, IComparer<T> comparer)
{
T[] testArr = new T[n];
T[] correctArr = new T[n];
Random rnd = new Random();
for (int i = 0; i < n; i++)
{
int t = rnd.Next(1, 1000);
testArr[i] = transform(t);
correctArr[i] = transform(t);
}
Array.Sort(correctArray, comparer);
return (testArr, correctArr);
}
And you can call GetArrays like this:
static void test<T>(ISorter<T> sorter, IComparer<T> intComparer)
{
var (correctArray, testArray) = RandomHelper.GetArrays(10, x => x, intComparer);
sorter.Sort(testArray, intComparer);
Console.WriteLine(string.Join(",", testArray));
Console.WriteLine(string.Join(",", correctArray));
}
In following struct, I'm using function to follow strategy pattern.
this is a simple range enumerator.
if negative length is passed, it will enumerate reversely.
How ever it does not work as expected. when _move call is returned, Position remains unchanged.
I guess I know the reason, its because struct is being copied somewhere. but I cant seem to find where copy is being made.
(using class instead of struct is not answer that I'm looking for.)
internal struct RangeEnumerator<T> : IEnumerator<T>
{
private readonly Func<bool> _move;
private readonly IReadOnlyList<T> _source;
private readonly int _start;
private readonly int _end;
// position of enumerator. not actual index. negative if reversed
public int Position { get; private set; }
public RangeEnumerator(IReadOnlyList<T> source, int start, int length)
{
start = Math.Min(Math.Max(start, 0), source.Count);
_source = source;
_start = start;
_end = Math.Min(Math.Max(length + start, 0), source.Count);
Position = -Math.Sign(length);
_move = null;
_move = length >= 0 ? (Func<bool>) this.MoveNextImpl : this.MovePrevImpl;
}
public bool MoveNext() => _move();
public void Reset() => Position = -1;
public T Current => _source[Position + _start];
object IEnumerator.Current => Current;
private bool MoveNextImpl() => ++Position + _start < _end;
private bool MovePrevImpl() => --Position + _start >= _end;
void IDisposable.Dispose()
{
}
}
Testing: for quick test, use the following code and debug.
public static class Program
{
public static void Main(string[] args)
{
var list = new List<int> {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
var enumerator = new RangeEnumerator<int>(list, 3, 5); // 3 to 8 exclusive
foreach (var x in enumerator.AsEnumerable(0))
{
Console.WriteLine(x);
}
}
}
internal static class EnumeratorExtensions
{
public static StructEnumerable<TEnumerator, T> AsEnumerable<TEnumerator, T>(this TEnumerator enumerator, T _) where TEnumerator : struct, IEnumerator<T>
{
// struct copy doesn't matter since we didn't start enumerating yet.
return new StructEnumerable<TEnumerator, T>(enumerator);
}
}
// Enumerable to be used by foreach.
internal struct StructEnumerable<TEnumerator, T> where TEnumerator : struct, IEnumerator<T>
{
private TEnumerator _enumerator;
public StructEnumerable(TEnumerator enumerator)
{
// struct copy doesn't matter since we didn't start enumerating yet.
_enumerator = enumerator;
}
public TEnumerator GetEnumerator()
{
// struct copy doesn't matter since we didn't start enumerating yet.
return _enumerator;
}
}
The issue is here.
_move = length >= 0 ? (Func<bool>) this.MoveNextImpl : this.MovePrevImpl;
In first view, it seems that you are using method group that will actually act on current value. but it doesn't. compiler is silently making a copy of struct when using instance method groups.
I found that you cant use this inside anonymous methods, delegates or lambda expressions. the reason is explained here.
You must copy this in local variable and use that local variable inside lambda instead. the same thing is happening when using instance method groups, but silently. it would be nice if compiler would throw a warning here.
anyway the solution is to use static method groups. If there are better solutions, Id like to know. (using class instead of struct is not answer that I'm looking for.)
internal struct RangeEnumerator<T> : IEnumerator<T>
{
private readonly MoveStrategy _move;
private readonly IReadOnlyList<T> _source;
private readonly int _start;
private readonly int _end;
// position of enumerator. not actual index. negative if reversed
public int Position { get; private set; }
public RangeEnumerator(IReadOnlyList<T> source, int start, int length)
{
start = Math.Min(Math.Max(start, 0), source.Count);
_source = source;
_start = start;
_end = Math.Min(Math.Max(length + start, 0), source.Count);
Position = -Math.Sign(length);
_move = null;
// no this, therefor no copy
_move = length >= 0 ? (MoveStrategy)MoveNextImpl : MovePrevImpl;
}
public bool MoveNext() => _move(ref this);
public void Reset() => Position = -1;
public T Current => _source[Position + _start];
object IEnumerator.Current => Current;
private static bool MoveNextImpl(ref RangeEnumerator<T> v) => ++v.Position + v._start < v._end;
private static bool MovePrevImpl(ref RangeEnumerator<T> v) => --v.Position + v._start >= v._end;
private delegate bool MoveStrategy(ref RangeEnumerator<T> v);
void IDisposable.Dispose()
{
}
}