I have a problem with a school task.
"Let's say class List are constructors to generate random arrays.
Class List1 inherits from class List and uses IComparable to compare first elements, then second ones etc. (blank is a 0) {1,1,1}<{1,2}<{2}
Class List2 inherits likewise and compares sizes of arrays by size. If sizes are the same, check like in List1 {1,2,3}<{1,2,3,4}<{2,2,3,4}"
I made class List.
public List(int b)
{
tabb = new int[b];
for (int i = 0; i < b; i++)
tabb[i] = r1.Next(0, 100);
}
I noticed that inheriting from List to List1 the constructors are not inherited, so i dont know where and how to use IComparable
class List1 : List,IComparable<List1>
{
public int CompareTo(List1 x){
return this.CompareTo(x);
}
}
I noticed that inheriting from List to List1 the constructors are not inherited, so i dont know where and how to use IComparable
I can't comprehend that sentence as a single question, as the lack of constructors being inherited seems completely independent to me of how to use IComparable<T>.
So, let's address the two questions separately:
You are correct that constructors are not inherited. That is, while they still exist, they are callable only by the derived type, and not directly usable by outside code. If a base class does not have a parameterless constructor, then as the implementer of the derived class, it is your responsibility to provide a constructor and then call the appropriate base class constructor (every class will have some constructor). For example:
class List1 : List
{
public List1(int count) : base(count) { }
}
(I'm assuming here that List is some type other than the .NET List<T> type, i.e. it's not generic and is defined in your own context.)
In this way, you provide the necessary constructor, and ensure that the correct base constructor is called, by using : base(count) to pass the parameter value to your constructor.
How to use IComparable<T>. It seems to me that this is the crux of your assignment. I would be doing you a disservice to write the code for you. However, I'll try to elaborate on the instructions to help you understand what they seem to be asking (of course, your teacher is the best person for you to receive this advice from).
You have two different assignments here. Both require that you implement the interface IComparable<T>, so the first thing you need to do is make sure you understand what it means to implement an interface. Do you? An interface is a kind of "contract". In any interface declaration, there are described the members that an implementation of that interface is required to provide. If you look at the definition of IComparable<T>, you'll see it requires implementation of just one member: a CompareTo() method.
So, your assignment comes down to how to implement that method for each of the two required subclasses, List1 and List2. The basic idea of the implementation is the same for both, but the specifics are different.
In the first case, the comparison will order the two instances of List1 according to the contents of the collection where the order of those instances is determined by the ordering of the first non-equal element in the same position of the array in each instance. In the examples given, {1, 1, 1} is treated as "less than" {1, 2} because when you compare the elements at each position for each instance of List1, the first corresponding position where the elements are different is the second position (index 1), where {1, 1, 1} has the value 1 and {1, 2} has the value 2. The value 1 is less than the value 2, so the whole instance of {1, 1, 1} is "less than" the whole instance of {1, 2}. (Unfortunately, the assignment as described in your post is not clear on how to order instances where the underlying list of one is shorter than the underlying list of the other, but has exactly the same values in those element positions. I would make the shorter list be treated as "less than", but that's not unambiguously the only valid way to do it.)
In the second part of the assignment, implementing List2, the only thing that's being compared is the length of the list. This should be much easier to implement than the first part of the assignment, because you have only a single value to compare in each List2 instance, i.e. tabb.Length.
Note that in both cases, you can take advantage of the fact that int also implements IComparable<T>, so you can use its CompareTo() method to determine whether corresponding values in each instance of your class are less than, equal to, or greater than each other.
I hope that that's enough to get you pointed in the right direction. If you need more help than that, you probably should just consult with your instructor. They will know exactly how much help they want to provide to you, while remaining short of actually doing the assignment for you.
Sorry, I didn't mean to go all out on this. But then it just happened. It's late. It interested me, especially the need to be able to test it even though the requirement for random numbers makes it difficult to test.
The solution I came do was to separate the list from how it gets populated. That way for test purposes I can substitute a "populator" that inserts exactly the values I want. That way I can create the scenarios for testing.
// This is the base list - it just requires something to populate it.
public class IntegerList : List<int>
{
public IntegerList(IIntegerListPopulator populator, int size)
{
populator.PopulateList(this, size);
}
}
// Interface and implementation to populate a list with random numbers.
public interface IIntegerListPopulator
{
void PopulateList(List<int> target, int size);
}
public class RandomIntegerListPopulator : IIntegerListPopulator
{
public void PopulateList(List<int> target, int size)
{
var random = new Random();
for (var i = 0; i < size; i++)
{
target.Add(random.Next(0, 100));
}
}
}
// Compares by values, but the populator is injected - needed so that
// the class can be tested.
public class IntegerListThatComparesByValues : IntegerList, IComparable<IntegerListThatComparesByValues>
{
public IntegerListThatComparesByValues(IIntegerListPopulator populator, int size)
: base(populator, size)
{ }
public int CompareTo(IntegerListThatComparesByValues other)
{
return new IntegerListValueComparer().Compare(this, other);
}
}
// Class to perform comparisons by value. There's no real point
// in implementing IComparer since I'm not using it that way,
// but it doesn't hurt.
public class IntegerListValueComparer : IComparer<IntegerList>
{
public int Compare(IntegerList x, IntegerList y)
{
// I made this part up. I don't actually know how
// you want to handle nulls.
if (x == null && y == null) return 0;
if (x == null) return 1;
if (y == null) return -1;
// Always compare the longer one to the shorter.
// if this one is shorter, do the reverse comparison
// and reverse the result.
if (y.Count < x.Count) return -Compare(y, x);
if (x.SequenceEqual(y)) return 0;
for (var index = 0; index < x.Count; index++)
{
var comparison = x[index].CompareTo(y[index]);
if (comparison != 0) return comparison;
}
// If the other list is longer than this one, then assume
// that the next element of this list is 0.
return -y[x.Count];
}
}
public class IntegerListThatComparesByLength : IntegerList, IComparable<IntegerListThatComparesByLength>
{
public IntegerListThatComparesByLength(IIntegerListPopulator populator, int size)
: base(populator, size)
{
}
public int CompareTo(IntegerListThatComparesByLength other)
{
var comparisonByCount = Count.CompareTo(other?.Count ?? 0);
return comparisonByCount != 0
? comparisonByCount
: new IntegerListValueComparer().Compare(this, other);
}
}
// *************************************************************
// These are the concrete classes specified in the requirements.
// *************************************************************
public class RandomIntegerListThatComparesByValues :
IntegerListThatComparesByValues
{
public RandomIntegerListThatComparesByValues(int size)
: base(new RandomIntegerListPopulator(), size)
{ }
}
public class RandomIntegerListThatComparesByLength :
IntegerListThatComparesByLength
{
public RandomIntegerListThatComparesByLength(int size)
: base(new RandomIntegerListPopulator(), size)
{ }
}
// *************************************************************
// The rest is all testing.
// *************************************************************
// Allows me to create class instances that contain the numbers
// I specify instead of random numbers so that I can create
// test cases.
public class IntegerListPopulatorTestDouble : IIntegerListPopulator
{
private readonly int[] _values;
public IntegerListPopulatorTestDouble(params int[] values)
{
_values = values;
}
public void PopulateList(List<int> target, int size)
{
target.AddRange(_values.Take(size));
}
}
[TestClass]
public class IntegerListThatComparesByValuesTests
{
[TestMethod]
public void EmptyListsAreEqual()
{
var list1 = new IntegerListThatComparesByValues(new IntegerListPopulatorTestDouble(), 0 );
var list2 = new IntegerListThatComparesByValues(new IntegerListPopulatorTestDouble(), 0);
Assert.AreEqual(0, list1.CompareTo(list2));
}
[TestMethod]
public void ListsWithSameValuesAreEqual()
{
var list1 = new IntegerListThatComparesByValues(new IntegerListPopulatorTestDouble(1,2,3), 3);
var list2 = new IntegerListThatComparesByValues(new IntegerListPopulatorTestDouble(1,2,3), 3);
Assert.AreEqual(0, list1.CompareTo(list2));
}
[TestMethod]
public void ListsOfSameLengthComparedByFirstNonEqualValue()
{
var list1 = new IntegerListThatComparesByValues(new IntegerListPopulatorTestDouble(1, 2, 4), 3);
var list2 = new IntegerListThatComparesByValues(new IntegerListPopulatorTestDouble(1, 2, 3), 3);
Assert.IsTrue(list1.CompareTo(list2) > 0);
}
[TestMethod]
public void MissingElementsOfListAreSortedAsZeros()
{
var list1 = new IntegerListThatComparesByValues(new IntegerListPopulatorTestDouble(1, 2, 3, 4), 4);
var list2 = new IntegerListThatComparesByValues(new IntegerListPopulatorTestDouble(1, 2, 3), 3);
var comparison = list1.CompareTo(list2);
Assert.IsTrue(comparison > 0);
comparison = list2.CompareTo(list1);
Assert.IsTrue(comparison < 0);
}
[TestMethod]
public void MissingElementsOfListAreSortedAsZeros_Case2()
{
var list1 = new IntegerListThatComparesByValues(new IntegerListPopulatorTestDouble(1, 2, 3, -4), 4);
var list2 = new IntegerListThatComparesByValues(new IntegerListPopulatorTestDouble(1, 2, 3), 3);
Assert.IsTrue(list1.CompareTo(list2) < 0);
Assert.IsTrue(list2.CompareTo(list1) > 0);
}
}
[TestClass]
public class IntegerListThatComparesByLengthTests
{
[TestMethod]
public void ListsAreComparedByLength()
{
var list1 = new IntegerListThatComparesByLength(new IntegerListPopulatorTestDouble(1, 2, 3, 4), 4);
var list2 = new IntegerListThatComparesByLength(new IntegerListPopulatorTestDouble(1, 2, 3), 3);
Assert.IsTrue(list1.CompareTo(list2) > 0);
Assert.IsTrue(list2.CompareTo(list1) < 0);
}
[TestMethod]
public void ListsOfEqualLengthAreComparedByValue()
{
var list1 = new IntegerListThatComparesByLength(new IntegerListPopulatorTestDouble(1, 2, 4), 3);
var list2 = new IntegerListThatComparesByLength(new IntegerListPopulatorTestDouble(1, 2, 3), 3);
Assert.IsTrue(list1.CompareTo(list2) > 0);
Assert.IsTrue(list2.CompareTo(list1) < 0);
}
}
I don't know if they teach unit testing in school, but this illustrates why they should. While the logic isn't incredibly difficult, it's likely that the first stab at it isn't going to be perfect. Without creating some test cases to run against this, how could you know if you got it right? How would your instructor know? What if you fix one bug but in doing so break the other test case? And then if you have to debug, every single time you debug you get different random numbers. Scary.
(It was the randomness that really threw me off. If the numbers are always random, how does the instructor expect to observe the results and know that they're correct? It's possible but eyeballing it isn't the most reliable way to know that it works.)
In real life, I wouldn't want to put even slightly complex logic into a production system without having these unit tests to tell me that it works as expected.
Also, when you read a description of requirements it can be confusing and unclear. But assuming that I understood the requirements, now you can look at the unit tests and get a clearer idea of what this code is supposed to do. Otherwise someone else could need to make changes, and if they can't tell what it's supposed to do, they can't tell if they're breaking it. If it turns out that I got the requirements wrong then I can change the tests to fit the right requirements. The tests will fail and then I modify the code until the tests pass.
Related
I am trying to add a few different members to a list, but when the list is added to it contains copies of only the last member added:
private PotentialSolution tryFirstTrack(PotentialSolution ps, List<PotentialSolution> possibleTracks)
{
for (Track trytrack = Track.Empty + 1; trytrack < Track.MaxVal; trytrack++)
{
if (validMove(ps.nextSide, trytrack))
{
ps.SetCell(trytrack);
possibleTracks.Add(ps);
}
}
return tryNextTrack(ps, possibleTracks);
}
The PotentialSolution class looks like this:
public class PotentialSolution
{
public Track[,] board;
public Side nextSide;
public int h;
public int w;
static int cellsPerSide;
static bool testing;
static int minTracks;
.....
public void SetCell(Track t)
{
board[h, w] = t;
}
}
So we are trying to make several copies of the board which only differ by which 'track' is placed in the current cell.
If I have a breakpoint at possibleTracks.Add(ps) then I can see by inspecting ps that the required cell contents is changing each time, as required.
But when the code reaches the next line (or the return statement), the cell content is the same in each member of the list (it's the last one that was added).
What I am doing wrong here? I have tried using an ArrayList and also a basic array instead, but get the same result. It's acting as though the board member is decared as static, but it's not.
[edit]
In response to those who suggested making copies of ps, you are correct and I had tried this before - but only tried single-stepping after the change and didn't run the full program (this method is used hundreds of times). When running the full program, making copies of ps certainly makes a difference to the result (although it's still not correct). The problem now, and why I didn't stick with using the copies, is that an added test still shows the list to contain the same versions of ps, even though the debugger has shown 2 or 3 different tracks being deployed:
private PotentialSolution tryFirstTrack(PotentialSolution ps, List<PotentialSolution> possibleTracks)
{
for (Track trytrack = Track.Empty + 1; trytrack < Track.MaxVal; trytrack++)
{
if (validMove(ps.nextSide, trytrack))
{
PotentialSolution newps = new PotentialSolution(ps);
newps.SetCell(trytrack);
possibleTracks.Add(newps);
}
}
// temporary test, can be removed
if (possibleTracks.Count >= 2)
{
PotentialSolution ps1 = new PotentialSolution(possibleTracks.First());
PotentialSolution ps2 = new PotentialSolution(possibleTracks.Last());
if (ps1.GetCell() != ps2.GetCell())
{
// should always get here but never does
int foo = 1;
}
}
return tryNextTrack(ps, possibleTracks);
}
By the way, Track and nextSide are just enum integers, they will be 0-6, and the list will contain 0,1,2,or 3 members, never more.
You are adding references to the same object: ps in possibleTracks.Add(ps)
You could add a constructor to PotentialSolution duplicating the class:
public class PotentialSolution
{
public Track[,] board;
public Side nextSide;
public int h;
public int w;
static int cellsPerSide;
static bool testing;
static int minTracks;
//.....
public PotentialSolution()
{
}
public PotentialSolution(PotentialSolution ps)
{
board = ps.board;
nextSide = ps.nextSide;
h = ps.h;
w = ps.w;
}
//.....
Then use:
private PotentialSolution tryFirstTrack(PotentialSolution ps, List<PotentialSolution> possibleTracks)
{
for (Track trytrack = Track.Empty + 1; trytrack < Track.MaxVal; trytrack++)
{
if (validMove(ps.nextSide, trytrack))
{
ps.SetCell(trytrack);
possibleTracks.Add(new PotentialSolution(ps)); // duplicate object
}
}
return tryNextTrack(ps, possibleTracks);
}
This creates a new instance of the class each time it is added to the list.
Consider giving the PotentialSolution type value semantics by making it a struct and implementing a Clone method, or a constructor that takes another PotentialSolution as an argument. Also, to clone a 2D array of value types, call Object.Clone() and cast the result to T[,].
When making a copy of your PotentialSolution, you'll need to make sure your clone your board array, because, in your case, each PotentialSolution keeps its own representation of the state of the board.
I feel like the critical part you're missing is how to shallow clone a 2D array, which in general, is:
T[,] copy = (T[,])original.Clone();
WARNING: Clone creates a shallow copy of the array. For value-types this copies the values of each element, so for your int-like "Track" type it does what you want, but for other readers who may be using reference-types (like classes) it does not clone each object referred to by each element of the array. The elements of the new array are just object references, and will still refer to the same objects referred to by the elements of the original array. See the documentation.
Full example below that changes the middle cell of a 3x3 board from A to B.
using System;
using System.Linq;
public enum Track { A, B, C }
public enum Side { X, Y, Z }
public struct PotentialSolution
{
public Track[,] board;
public Side nextSide;
public int h;
public int w;
public void SetCell(Track t)
{
board[h, w] = t;
}
public PotentialSolution(Track[,] board, Side nextSide, int h, int w)
{
this.board = (Track[,])board.Clone();
this.nextSide = nextSide;
this.h = h;
this.w = w;
}
public PotentialSolution Clone()
{
return new PotentialSolution(board, nextSide, h, w);
}
// This `ToString` is provided for illustration only
public override string ToString()
{
var range0 = board.GetLength(0);
var range1 = board.GetLength(1);
var b = board;
return string.Join(",",
Enumerable.Range(0, range0)
.Select(x => Enumerable.Range(0, range1)
.Select(y => b[x, y]))
.Select(z => "[" + string.Join(",", z) + "]"));
}
}
class Program
{
static void Main(string[] args)
{
Track[,] someBoard = new Track[3, 3];
PotentialSolution ps1 = new PotentialSolution(someBoard, Side.X, 1, 1);
ps1.SetCell(Track.A);
PotentialSolution ps2 = ps1.Clone();
ps2.SetCell(Track.B);
Console.WriteLine(ps1);
Console.WriteLine(ps2);
}
}
I'm filling in the blanks liberally, so please excuse any assumptions I have made that differ from your actual situation, because I have done so only to make this example self-contained. My ToString implementation and its usage of System.Linq is not necessary; it's purely for the purposes of displaying the 2D array in my example.
You always call SetCell on the same ps object you received as a parameter then add the same instance to the possibleTracks list. The result is: possibleTrack contains ps n times and because it is the same instance you used in each cycle it will have the last change you applied via SetCell call.
Not sure what you wanted to achieve but it looks you need a modified copy of ps in each cycle for adding to possibleTrack list. Making PotentialSolution a struct instead of class could be enough? Structs are copied in such a way but may hit your performance if PotentialSolution is big.
The board member will still generate the same problem, because despite ps will be copied but the board inside it will contain same Track references. The trick can be applied to Track too, but the performance issues may raise more.
Just implement a Clone on PotentialSolution to have fully detached instances of it, then call ````SetCell``` on cloned instance and add that instance to the list.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
Let's say I have a class like this:
public class Fraction
{
int numerator;
int denominator;
public Fraction(int n, int d)
{
// set the member variables
}
// And then a bunch of other methods
}
I want to initialize an array of them in a nice way, and this post is a big list of approaches that are error prone or syntactically cumbersome.
Of course an array constructor would be nice, but there's no such thing:
public Fraction[](params int[] numbers)
So I'm forced to use a method like
public static Fraction[] CreateArray(params int[] numbers)
{
// Make an array and pull pairs of numbers for constructor calls
}
which is relatively clunky, but I don't see a way around it.
Both forms are error prone because a user could mistakenly pass an odd number of parameters, maybe because s/he skipped a value, which would leave the function scratching its head wondering what the user actually wanted. It could throw an exception, but then the user would need to try/catch. I'd rather not impose that on the user if possible. So let's enforce pairs.
public static Fraction[] CreateArray(params int[2][] pairs)
But you can't call this CreateArray in a nice way, like
Fraction.CreateArray({0,1}, {1,2}, {1,3}, {1,7}, {1,42});
You can't even do
public static Fraction[] CreateArray(int[2][] pairs)
// Then later...
int[2][] = {{0,1}, {1,2}, {1,3}, {1,7}, {1,42}};
Fraction.CreateArray(numDenArray);
Note that this would work just fine in C++ (I'm pretty sure).
You're forced to do one of the following instead, which is abhorrent. The syntax is terrible and it seems really awkward to use a jagged array when all the elements have the same length.
int[2][] fracArray = {new int[2]{0,1}, /*etc*/);
Fraction.CreateArray(fracArray);
// OR
Fraction.CreateArray(new int[2]{0,1}, /*etc*/);
Similarly, Python-style tuples are illegal and the C# version is icky:
Fraction.CreateArray(new Tuple<int,int>(0,1), /*etc*/);
The use of a pure 2D array might take the following form, but it's illegal, and I'm sure there's no legal way to express it:
public static Fraction[] CreateArray(int[2,] twoByXArray)
// Then later...
Fraction[] fracArray =
Fraction.CreateArray(new int[2,4]{{0,1}, {1,2}, {1,3}, {1,6}});
This doesn't enforce pairs:
public static Fraction[] CreateArray(int[,] twoByXArray)
OK, how about
public static Fraction[] CreateArray(int[] numerators, int[] denominators)
But then the two arrays might have different lengths. C++ allows
public static Fraction[] CreateArray<int N>(int[N] numerators, int[N] denominators)
but, well, this isn't C++, is it?
This sort of thing is illegal:
public static implicit operator Fraction[](params int[2][] pairs)
and unworkable anyway, again because of the abhorrent syntax:
Fraction[] fracArray = new Fraction[](new int[2]{0,1}, /*etc*/ );
This might be nice:
public static implicit operator Fraction(string s)
{
// Parse the string into numerator and denominator with
// delimiter '/'
}
Then you can do
string[] fracStrings = new string[] {"0/1", /*etc*/};
Fraction[] fracArray = new Fraction[fracStrings.Length];
int index = 0;
foreach (string fracString in fracStrings) {
fracArray[index] = fracStrings[index];
}
I don't like this approach for five reasons. One, the implicit cast unavoidably instantiates a new object, but we already have a perfectly good one, namely the one we're trying to initialize. Two, it can be confusing to read. Three, it forces you to do explicitly what I wanted to encapsulate in the first place. Four, it leaves room for bad formatting. Five, it involves one-time parsing of string literals, which is more like a practical joke than good programming style.
The following also requires wasteful instantiation:
var fracArray = Array.ConvertAll(numDenArray, item => (Fraction)item);
The following use of a property has the same problem unless you use those terrible jagged arrays:
public int[2] pair {
set {
numerator = value[0];
denominator = value[1];
}
}
// Then later...
var fracStrings = new int[2,4] {{0,1}, /*etc*/};
var fracArray = new Fraction[fracStrings.Length];
int index = 0;
foreach (int[2,] fracString in fracStrings) {
fracArray[index].pair = fracStrings[index];
}
This variation doesn't enforce pairs:
foreach (int[,] fracString in fracStrings) {
fracArray[index].pair = fracStrings[index];
}
Again, this approach is big anyway.
These are all of the ideas I know how to derive. Is there a good solution?
I can't think of an elegant, and at the same time memory efficient solution for array.
But there is an elegant solution for list (and similar) utilizing the C# 6 collection initializer feature:
public static class Extensions
{
public static void Add(this ICollection<Fraction> target, int numerator, int denominator)
{
target.Add(new Fraction(numerator, denominator));
}
}
With that extension method in place, you can easily initialize a Fraction list for instance:
var list = new List<Fraction> { { 0, 1 }, { 1, 2 }, { 1, 3 }, { 1, 7 }, { 1, 42 } };
And of course, although not memory efficient, you can use it to initialize Fraction array either:
var array = new List<Fraction> { { 0, 1 }, { 1, 2 }, { 1, 3 }, { 1, 7 }, { 1, 42 } }.ToArray();
or even making it more concise by declaring a list derived class with implicit array conversion operator:
public class FractionList : List<Fraction>
{
public static implicit operator Fraction[](FractionList x) => x?.ToArray();
}
and then use
Fraction[] array = new FractionList { { 0, 1 }, { 1, 2 }, { 1, 3 }, { 1, 7 }, { 1, 42 } };
You could create a fraction array builder with a fluent interface. It would lead to something like
public class FractionArrayBuilder
{
private readonly List<Fraction> _fractions = new List<Fraction>();
public FractionArrayBuilder Add(int n, int d)
{
_fractions.Add(new Fraction(n, d));
return this;
}
public Fraction[] Build()
{
return _fractions.ToArray();
}
}
which can be called using
var fractionArray = new FractionArrayBuilder()
.Add(1,2)
.Add(3,4)
.Add(3,1)
.Build();
which is an easy to understand statement.
I have made a fiddle to demonstrate.
The most succinct way I can think of for your particular example involves writing an implicit operator for the Fraction class:
public sealed class Fraction
{
public Fraction(int n, int d)
{
Numerator = n;
Deniminator = d;
}
public int Numerator { get; }
public int Deniminator { get; }
public static implicit operator Fraction(int[] data)
{
return new Fraction(data[0], data[1]);
}
}
Then you can initialise it like this:
var fractions = new Fraction[]
{
new [] {1, 2},
new [] {3, 4},
new [] {5, 6}
};
Unfortunately you still need the new [] on each line, so I don't think this gains very much over the normal array initialisation syntax:
var fractions = new []
{
new Fraction(1, 2),
new Fraction(3, 4),
new Fraction(5, 6)
};
I suppose you could write a "local" Func<> with a short name to simplify the initialisation somewhat:
Func<int, int, Fraction> f = (x, y) => new Fraction(x, y);
var fractions = new []
{
f(1, 2),
f(3, 4),
f(5, 6)
};
The drawback is that you'd need to add that extra line (initialising a Func<>) wherever you wanted to initialise the array - or have a private static method in the class instead - but then that method would be in scope throughout the class, which isn't ideal if it has a single-letter name.
However, the advantage of this approach is that it is very flexible.
I toyed with the idea of calling the inline function _, but I'm really not sure about that...
Func<int, int, Fraction> _ = (x, y) => new Fraction(x, y);
var fractions = new []
{
_(1, 2),
_(3, 4),
_(5, 6)
};
Does NUnit provide a constraint to find whether the actual value is the element of a given enumerable or array, in other words, that it is equal to any of multiple expected values? Something like:
Assert.That(actual, Is.EqualToAnyOf(new[] { 1, 2, 3 }))
That is, to point out, the actual is a single value. I expect the value to be either 1, 2, or 3. The assertion
Assert.That(actual, Contains.Element(expected))
checks logically the same, but it is the opposite intention: Here we have a collection of actual values and expect one value to be in it.
Furthermore, I found these but they all don't fit:
Assert.That(actual, Is.EqualTo(expected)) // only allows one value
Assert.That(actual, Is.InRange(start, end)) // only works for consecutive numbers
Assert.That(actual, Is.SubsetOf(expected)) // only works if actual is an enumerable
Assert.That(expected.Contains(actual)) // meaningless "expected: true but was: false" message
CollectionAssert should be what you need if I am not overlooking something. It is as simple as:
CollectionAssert.Contains(IEnumerable expected, object actual);
However, there seems to be several ways to achieve your goal, such as:
[Test]
public void CollectionContains()
{
var expected = new List<int> { 0, 1, 2, 3, 5 };
var actual = 5;
CollectionAssert.Contains(expected, actual);
Assert.That(expected, Contains.Item(actual));
}
Above assertions should basically assert the same and could be used interchangeably.
Edit:
Question was modified, stating that Assert.That(expected, Contains.Item(actual)); is not valid even though it logically tests the same thing.
There is a way to do this built in to NUnit, using the Or constraint:
Assert.That(actual, Is.EqualTo(1).Or.EqualTo(2).Or.EqualTo(3))
If your list is more dynamic, you can build your list of Ors like this:
var expected = new[] { 1, 2, 3 };
var constraints = Is.EqualTo(expected[0]);
for(var i = 1; i < expected.Length; i++)
constraints = constraints.Or.EqualTo(expected[i]);
Assert.That(actual, constraints);
That latter answer doesn't read as well in the fluid syntax, but does achieve the dynamic building of or constraints. You could probably wrap that in a custom constraint as patrick-quirk demonstrated in order to achieve a more readbale fluid syntax, but that's up to you.
I know this is an old question, bu I have a maybe better (and native) suggestion.
With NUnit 3.x (I'm on 3.10.1) you can use Is.AnyOf:
Assert.That(
actualValue,
Is.AnyOf(expectedValue1, expectedValue2, expectedValue3),
"My error message");
The only way I could see to accomplish this is by creating your own constraint. It's pretty straightforward to do though.
The constraint class itself:
public class OneOfValuesConstraint : EqualConstraint
{
readonly ICollection expected;
NUnitEqualityComparer comparer = new NUnitEqualityComparer();
public OneOfValuesConstraint(ICollection expected)
: base(expected)
{
this.expected = expected;
}
public override bool Matches(object actual)
{
// set the base class value so it appears in the error message
this.actual = actual;
Tolerance tolerance = Tolerance.Empty;
// Loop through the expected values and return true on first match
foreach (object value in expected)
if (comparer.AreEqual(value, actual, ref tolerance))
return true;
// No matches, return false
return false;
}
// Overridden for a cleaner error message (contributed by #chiccodoro)
public override void WriteMessageTo(MessageWriter writer)
{
writer.DisplayDifferences(this);
}
public override void WriteDescriptionTo(MessageWriter writer)
{
writer.Write("either of ");
writer.WriteExpectedValue(this.expected);
}
}
And to make it fluent, create a static method to wrap it (contributed by #chicodorro):
public static class IsEqual
{
public static OneOfValuesConstraint ToAny(ICollection expected)
{
return new OneOfValuesConstraint(expected);
}
}
Then to use it:
int[] expectedValues = new[] { 0, 1, 2 };
Assert.That(6, IsEqual.ToAny(expectedValues));
Fails with the message:
Expected: either of < 0, 1, 2 >
But was: 6
I can type
Square[,,,] squares = new Square[3, 2, 5, 5];
squares[0, 0, 0, 1] = new Square();
In fact, I expect I could keep going adding dimensions to Int.MaxValue though I have no idea how much memory that would require.
How could I implement this variable indexing feature in my own class? I want to encapsulate a multi dimensional array of unknown dimensions and make it available as a property thus enabling indexing in this manner. Must I always know the size in which case how does Array work?
EDIT
Thanks for the comments, here is what I ended up with - I did think of params but didn't know where to go after that not knowing about GetValue.
class ArrayExt<T>
{
public Array Array { get; set; }
public T this[params int[] indices]
{
get { return (T)Array.GetValue(indices); }
set { Array.SetValue(value, indices);}
}
}
ArrayExt<Square> ext = new ArrayExt<Square>();
ext.Array = new Square[4, 5, 5, 5];
ext[3, 3, 3, 3] = new Square();
TBH I don't really need this now. I was just looking for a way to extend Array to initialize its elements having resolved to avoid for loop initialization code outside the class whenever I was using a multi array (mainly in unit tests). Then I hit intellisense and saw the Initialize method...though it restricts me to a default constructor and value types. For reference types an extension method would be required. Still I learnt something and yes, there was a runtime error when I tried an array with more than 32 dimensions.
Arrays types are magic – int[] and int[,] are two different types, with separate indexers.
These types are not defined in source code; rather, their existence and behavior are described by the spec.
You would need to create a separate type for each dimensionality – a Matrix1 class with a this[int], a Matrix2 class with a this[int, int], and so on.
You could use varargs:
class Squares {
public Square this[params int[] indices] {
get {
// ...
}
}
}
You'd have to handle the fact indices can have an arbitrary length yourself, in whicheevr way you feel is appropriate. (E.g. check the size of indices against the array rank, type it as Array and use GetValue().)
use the this[] operator:
public int this[int i, int j]
{
get {return 1;}
set { ; }
}
Note that you can't have a variable number of dimensions in one operator - you have to code each method separately:
public int this[int i, int j, int k]
{
get {return 1;}
set { ; }
}
public int this[int i, int j]
{
get {return 1;}
set { ; }
}
public int this[int i]
{
get {return 1;}
set { ; }
}
I expect I could keep going adding dimensions to Int.MaxValue
You'd be wrong:
An array can have a maximum of 32 dimensions.
I have this list
var list = new List { 3, 1, 0, 5 };
I want to swap element 0 with 2
output
0, 1, 3, 5
If you just want it sorted, I'd use List.Sort().
If you want to swap, there is no built in method to do this. It'd be easy to write an extension method, though:
static void Swap<T>(this List<T> list, int index1, int index2)
{
T temp = list[index1];
list[index1] = list[index2];
list[index2] = temp;
}
You could then do:
list.Swap(0,2);
Classic swap is...
int temp = list[0];
list[0] = list[2];
list[2] = temp;
I don't think Linq has any 'swap' functionality if that's what you're looking for.
In the case that something is not directly supported ...make it so number 1!
Take a look at the concept of "extension methods". With this you can easily make your list support the concept of Swap() (this applies to any time you want to extend the functionality of a class).
namespace ExtensionMethods
{
//static class
public static class MyExtensions
{
//static method with the first parameter being the object you are extending
//the return type being the type you are extending
public static List<int> Swap(this List<int> list,
int firstIndex,
int secondIndex)
{
int temp = list[firstIndex];
list[firstIndex] = list[secondIndex];
list[secondIndex] = temp;
return list;
}
}
}