from this reference : http://functionalprogrammingcsharp.com/honest-functions
I have learned to be more honest when defining method/function in C#.
It said that prefer pure function so that the function will always give the exact return type given in signature.
However when I try to apply it:
int Divide(int x, int y)
{
return x / y;
}
From the website:
The signature states that the function accepts two integers and returns another integer. But this is not the case in all scenarios. What happens if we invoke the function like Divide(1, 0)? The function implementation doesn't abide by its signature, throwing DivideByZero exception. That means this function is also "dishonest". How can we make this function an honest one? We can change the type of the y parameter (NonZeroInteger is a custom type which can contain any integer except zero):
int Divide(int x, NonZeroInteger y)
{
return x / y.Value;
}
I'm not sure what is the implementation of NonZeroInteger, they don't seem to give any implementation of NonZeroInteger in the website, should it check for 0 inside that class? And
I'm pretty sure if I call Divide(1, null) it will still show an error, thus making the function not honest.
Why honest function example in C# still not being honest?
Taking the example you've posted, and having read the link, if you want to make the function "honest" then you don't really need to create a new type, you could just implement the Try pattern:
bool TryDivide(int x, int y, out int result)
{
if(y != 0)
{
result = x / y;
return true;
}
result = 0;
return false;
}
This function basically fulfills the "honest" principle. The name says it will try to do division, and the resulting 'bool` says that it will indicate it is was successful.
You could create a struct NonZeroInteger but you're going to have to write a lot of code around it to make it act like a regular numeric type, and you'll probably come full circle. For example, what if you pass 0 to the NonZeroInteger constructor? Should it fail? Is that honest.
Also, struct type always have a default constructor, so if you're wrapping an int it's going to be awkward to avoid it being set to 0.
To make it honest, define a new data structure and check the status.
enum Status { OK, NAN }
class Data
{
public int Value { get; set; }
public Status Status { get; set; }
public static Data operator /(Data l, Data r)
{
if (r.Value == 0)
{
// Value can be set to any number, here I choose 0.
return new Data { Value = 0, Status = Status.NAN };
}
return new Data { Value = l.Value / r.Value, Status = Status.OK };
}
public override string ToString()
{
return $"Value: {Value}, Status: {Enum.GetName(Status.GetType(), Status)}";
}
}
class Test
{
static Data Divide(Data left, Data right)
{
return left / right;
}
static void Main()
{
Data left = new Data { Value = 1 };
Data right = new Data { Value = 0 };
Data output = Divide(left, right);
Console.WriteLine(output);
}
}
The notion of "honest function" still has room for interpretation, and I don't want to debate about it here, would be more opinion than actual useful answer.
To specifically answer your example, you could declare NonZeroInteger as a ValueType, with struct instead of class.
A value type is non-nullable (except if you explicitly specify the nullable version with a ?). No null-problem in this case. By the way, int is an example of value type (it's an alias for System.Int32, to be exact).
As some have pointed out, it could lead to other difficulties (struct has always a default constructor that initialize all fields to their default, and the default for an int is 0...)
For an mid-experienced programmer, this kind of example does not need to be explicitly implemented in the article to be understood on principle.
However, if you are unsure about it, it would definitely be a good programming learning exercise, I strongly encourage you to implement it yourself! (And create unit tests to demonstrate that your function has no "bug", by the way)
This NonZeroInteger is just a "symbol", which just represents the idea, not conrete implementation.
Surely, author could provide implemenetation of such construct, but its name servers just right for the sake of an article.
Possible implememntation might be:
public class NonZeroInteger
{
public int Value { get; set; }
public NonZeroInteger(int value)
{
if( value == 0 ) throw new ArgumentException("Argument passed is zero!");
Value = value;
}
}
But it's just pushing dishonesty somewhere else (in terms of an article), because constructor should return an object, not throw exception.
IMO, honesty is not achievable, because it's just moving dishonesty somewhere else, as shown in this example.
After reading it thoroughly a lot of times..
I found that his second option on the website is honest, and the first one is wrong.
int? Divide(int x, int y)
{
if (y == 0)
return null;
return x / y;
}
Edit: got idea from another article, basically mimicking the F# path, something like this:
Option<int> Divide(int x, int y)
{
if (y == 0)
return Option<int>.CreateEmpty();
return Option<int>.Create(x / y);
}
public class Option<T> : IEnumerable<T>
{
private readonly T[] _data;
private Option(T[] data)
{
_data = data;
}
public static Option<T> Create(T element)
{
return new Option<T>(new T[] { element });
}
public static Option<T> CreateEmpty()
{
return new Option<T>(new T[0]);
}
public IEnumerator<T> GetEnumerator()
{
return ((IEnumerable<T>) _data).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public void Match(Action<T> onSuccess, Action onError) {
if(_data.Length == 0) {
onError();
} else {
onSuccess(_data[0]);
}
}
}
Ref: https://www.matheus.ro/2017/09/26/design-patterns-and-practices-in-net-option-functional-type-in-csharp/
to call:
public void Main() {
Option<int> result = Divide(1,0);
result.Match(
x => Console.Log(x),
() => Console.Log("divided by zero")
)
}
I just want to mention that NonZeroInteger can definitely be implemented honestly using a variation on Peano numbers:
class NonZeroInteger
{
/// <summary>
/// Creates a non-zero integer with the given value.
/// (This is private, so you don't have to worry about
/// anyone passing in 0.)
/// </summary>
private NonZeroInteger(int value)
{
_value = value;
}
/// <summary>
/// Value of this instance as plain integer.
/// </summary>
public int Value
{
get { return _value; }
}
private readonly int _value;
public static NonZeroInteger PositiveOne = new NonZeroInteger(1);
public static NonZeroInteger NegativeOne = new NonZeroInteger(-1);
/// <summary>
/// Answers a new non-zero integer with a magnitude that is
/// one greater than this instance.
/// </summary>
public NonZeroInteger Increment()
{
var newValue = _value > 0
? _value + 1 // positive number gets more positive
: _value - 1; // negative number gets more negative
return new NonZeroInteger(newValue); // can never be 0
}
}
The only tricky part is that I've defined Increment so that it works with both positive and negative integers. You can create any integer value you want except zero, and no exceptions are ever thrown, so this class is totally honest. (I'm ignoring overflow for now, but I don't think it would be a problem.)
Yes, it requires you to increment by one repeatedly to build large integers, which is extremely inefficient, but that's OK for a toy class like this one. There are probably other honest implementations that would be more efficient (e.g. using a uint as an offset from +1 or -1), but I'll leave that as an exercise for the reader.
You can test it like this:
class Test
{
static int Divide(int x, NonZeroInteger y)
{
return x / y.Value;
}
static void Main()
{
var posThree = NonZeroInteger.PositiveOne
.Increment()
.Increment();
Console.WriteLine(Divide(7, posThree));
var negThree = NonZeroInteger.NegativeOne
.Increment()
.Increment();
Console.WriteLine(Divide(7, negThree));
}
}
Output is:
2
-2
Honestly this is, IMO, overkill, but if I were to do a "Honest" method. I would do something like this. Instead of creating an entire new class. This is not a recommendation of what to do, and could easily cause issues in your code later. The best way to handle this, IMO, is to use the function and catch the exception outside of the Method. This is an "Honest" method in the fact that it always returns an integer, but it could return false values back.
int Divide(int x, int y)
{
try
{
return x / y;
}
catch (DivideByZeroException)
{
return 0;
}
}
Related
this is a problem I'm not sure how to call it or how name the things I want to do but hopefully the code examples can speak for themselves. I come from a PHP background and am learning .NET Core 2.2/3.0. Something I'm running into right now though is how I can avoid some code duplication when creating similar classes. For example I want to create multiple value objects that basically just contain strings, but each value object has different constraints. In most cases however the only constraint differences are in the length.
So in PHP I would do something like this:
abstract class Text
{
abstract public static function maxCharacters(): int;
protected $value;
public function __construct(string $text)
{
if (mb_strlen($text) > static::maxCharacters()) {
throw new LengthException(sprintf('Too many characters, the max is %d.', static::maxCharacters()));
}
$this->value = $text;
}
public function value(): string
{
return $this->value;
}
}
class Name extends Text
{
public static function maxCharacters(): int
{
return 50;
}
}
class Description extends Text
{
public static function maxCharacters(): int
{
return 1000;
}
}
It's not the best example of inheritance, but the goal is to illustrate the point in that I would like to have 1 place where I can put my validation logic, and then in the subclass only have to define the parameters of the validation and not the actual logic to perform the validation.
Since we're dealing with value objects here I assume that in C# it would be best to use a (readonly) struct. So, without any inheritance, what I ended up with as the C# equivalent is:
public readonly struct Name
{
private const int MAX_CHARACTERS = 50;
public string Value
{
get { return this.Value; }
set
{
if (value.Length > Name.MAX_CHARACTERS)
{
throw new ArgumentOutOfRangeException(String.Format("Too many characters, the max is {0}.", Name.MAX_CHARACTERS));
}
this.Value = value;
}
}
public Name(string name) => this.Value = name;
}
public readonly struct Description
{
private const int MAX_CHARACTERS = 1000;
public string Value
{
get { return this.Value; }
set
{
if (value.Length > Description.MAX_CHARACTERS)
{
throw new ArgumentOutOfRangeException(String.Format("Too many characters, the max is {0}.", Description.MAX_CHARACTERS));
}
this.Value = value;
}
}
public Description(string description) => this.Value = description;
}
But as you can see without inheritance that's a lot of copy/paste, and copy/paste is something I prefer to avoid. The only alternative I could think of is to create a separate TextValidator class or something that I can call from the set to which I would only have to pass the max number of characters, but that would still leave me with more copy/paste than I'd prefer.
How would you write something like this in C# with as little copy/paste as possible?
It seems like you've got the basics of inheritance understood in your PHP example; I'd just suggest doing a bit of reading on the syntax in C#.
For what it's worth, the following would do the trick:
public abstract class Text{
public string Value { get; }
public Text(string val) {
if (val.Length > MAX) throw new Exception();
Value = val;
}
protected abstract int MAX{get;}
}
public class Name : Text{
public Name(string val): base(val) { }
protected override int MAX => 50;
}
public class Description : Text
{
public Description(string val) : base(val) { }
protected override int MAX => 1000;
}
I'll also add a footnote to say be careful calling abstract methods/properties from a class constructor (which is what I'm doing here). If, for example, the value of MAX is a computed value which depends on the object already having been initialized, you could run into some issues. In this case though, it won't be a problem.
Imagine a class which can, in principle, be created by specifying the value of one of two properties, both of which happen to have the same type. The following code accomplishes this by using a combination of named and optional parameters to discriminate between the two constructors:
class Program
{
static void Main()
{
//Note: these 2 ctors are distinguished only by the argument naming convention:
thing thingWithMass = new thing(mass: 10);
thing thingWithVolume = new thing(vol: 25);
}
class thing
{
int Density = 3;
int Mass;
int Vol;
public thing(int mass)
{
Mass = mass;
Vol = Mass/Density;
}
// Note the use of the optional variable to distinguish this ctor:
public thing(int vol, bool isVol=true)
{
Vol = vol;
Mass = Vol * Density;
}
}
}
So (somewhat surprisingly) this code compiles and works perfectly, but is it bad form? It seems a bit like trickery, and I'm wondering if there is a lurking danger that isn't readily apparent to me? Does it smell?
NOTE: In this particular case, I realize that I could accomplish essentially the same thing with a single constructor that looks like this:
public thing(int mass=0, int vol=0) //plus a couple of if() statements in the body
but in my real situation there are quite a few other parameters involved, and combining them all into one constructor gets a bit unwieldy and hard to read.
If your class has many constructors with very different logic and conflicting types of arguments, consider using static factory methods:
public static Thing CreateFromMass(int mass)
{
return new Thing(mass, 0);
}
public static Thing CreateFromVol(int vol)
{
return new Thing(0, vol);
}
You can make your constructor non-public if you use factory methods like this.
Distinguishing constructors based on parameter names, while possible, is not recommended, because it is very uncommon in C#. Note that you are also forced to use tricks with optional parameters to achive this — a clear indicator that you are doing something wrong.
IMO it's a bit of a smell. What if a consumer calls thing(10, false). That has the unintended consequence of creating thing with the wrong value.
I can think of two possible solutions
1) Use a factory as described by Athari.
2) Create types for Mass and Volume. For example,
class Mass
{
private readonly int _mass;
public Mass(int mass) { _mass = mass; }
public int Value { get { return _mass; } }
}
class Volume
{
private readonly int _volume;
public Mass(int volume) { _volume = volume; }
public int Value { get { return _volume; } }
}
You can then change your signatures to
thing(Volume volume)
thing(Mass mass)
In response to your comment about simple arithmetic operations not working with the second approach, you can define implicit conversions to and from int for Mass and Volume.
abstract class Number
{
public static implicit operator int(Number number)
{
return number.Value;
}
public abstract int Value { get; set; }
}
internal class Mass : Number
{
public override int Value { get; set; }
public static implicit operator Mass(int val) { return new Mass(){ Value = val }; }
}
internal class Volume : Number
{
public static implicit operator Volume(int val) { return new Volume(){ Value = val }; }
public override int Value { get; set; }
}
var mass = new Mass { Value = 10 };
var volume = new Volume { Value = 20 };
int product = mass * volume; // should work
mass = 10 * 20; // should also work
I have a problem which takes a standard combination of inputs, however there are a several algorithms ('processors') which can solve it. The output is a Boolean. Each processor is only valid for one particular scenario, and there will never be more than one processor which is valid.
Each processor determines whether it is valid or not by having some initial inputs supplied to it. If it is valid, then it calculates some information based on those initial inputs, and stores it - since that information is useful in the final process. Then, if it is valid, then additional inputs are supplied to the processor and it returns an output.
If no processor is valid then a default answer is given.
So the algorithm is like this in pseudo code:
process(inputs)
for each processor
determine validity and get data
if valid
use data to output result
end if
end for
output default result
end
Here is a C# example, which isn't syntactically valid. And its just an example, in real life the inputs are more complex than strings and integers. The computation of the second input (int i in the contrived example) is executed repeatedly inside a loop, whereas the first input is only calculated once - hence the separation of whether a process if valid from what the result of the processor is. As an alternative to using an IEnumerable, we could have an array or list of processors.
public class ProcessController
{
public static IEnumerable<Processor<X>> GetProcessors<X>() where X: ProcessorInfo
{
yield return new ProcessorA();
yield return new ProcessorB();
}
public static bool Process<X>(String s, int i) where X : ProcessorInfo
{
foreach (Processor<X> processor in GetProcessors<X>())
{
X x = (X) processor.GetInfoIfCanProcess(s);
if (x != null)
{
return processor.GetResult(x, i);
}
}
return false;
}
}
public abstract class Processor<T> where T: ProcessorInfo
{
public abstract T GetInfoIfCanProcess(String s);
public abstract bool GetResult(T info, int i);
}
public interface ProcessorInfo
{
bool IsValid();
}
public class ProcessorA: Processor<ProcessorA.ProcessorInfoA>
{
public class ProcessorInfoA: ProcessorInfo
{
public bool IsValid()
{
//do something!
}
}
public override ProcessorInfoA GetInfoIfCanProcess(string s)
{
//do something!
}
public override bool GetResult(ProcessorInfoA info, int i)
{
//do something!
}
}
public class ProcessorB : Processor<ProcessorB.ProcessorInfoB>
{
public class ProcessorInfoB : ProcessorInfo
{
public bool IsValid()
{
//do something!
}
}
public override ProcessorInfoB GetInfoIfCanProcess(string s)
{
//do something!
}
public override bool GetResult(ProcessorInfoB info, int i)
{
//do something!
}
}
I am getting syntax errors in the GetProcessors method: Cannot implicitly convert type Play.ProcessorA to Play.Processor<X>. How can I get around this?
You are trying to couple a processor class and its processor info class using generics, which is problematic. You end up with a loose couping where you just cast the objects to what they should be, instead of making the generics assure that the types are correct.
I suggest that you avoid that problem by storing the info in the class itself. The code that runs the processor doesn't have to know anything about the information that the processor uses, it only has to know if the processor is valid or not.
Return a boolean instead of a ProcessorInfo object, and keep the relevant data in the Processor object. If the processor is valid, it has the data that it needs. If not, it will go away along with the data that it got from the first step when you go on to try the next processor.
The simplest way to fix this is using OfType:
private static IEnumerable<object> GetProcessors()
{
yield return new ProcessorA();
yield return new ProcessorB();
}
public static IEnumerable<Processor<X>> GetProcessors<X>() where X: ProcessorInfo
{
return GetProcessors.OfType<Processor<X>>();
}
Since Processor<X> is invariant there is no common type you can use, and since X is chosen outside the method you need to use a dynamic type check.
I read this answer: https://stackoverflow.com/a/9928643/16241
But I obviously don't understand it because I can't figure out why my method is impure. (The method in question is ToExactLocation()).
public struct ScreenLocation
{
public ScreenLocation(int x, int y):this()
{
X = x;
Y = y;
}
public int X { get; set; }
public int Y { get; set; }
public ExactLocation ToExactLocation()
{
return new ExactLocation {X = this.X, Y = this.Y};
}
// Other stuff
}
Incase you need it here is the exact location struct:
public struct ExactLocation
{
public double X { get; set; }
public double Y { get; set; }
// Various Operator Overloads, but no constructor
}
And this is how I call it:
someScreenLocation = MethodThatGivesAScreenLocation();
if (DestinationLocation == someScreenLocation.ToExactLocation())
{
// Do stuff
}
When I do that, ReSharper flags it with "Impure Method is called for readonly field of value type."
Why is it saying that? And what can I do to make it go away?
It's not pure because it does not return a value dependent only on its input. When the value of X or Y changes so does the return value of ToExactLocation, i.e., its output depends on internal, mutable state.
Additionally, the setters for X or Y in ExactLocation may mutate the input. The getters of ScreenLocation may as well.
someScreenLocation is a readonly field and is a value type. You are calling ToExactLocation on a value, i.e., a readonly field. When you access a reaodnly value type a copy is created as to avoid mutating the value itself. However, your call may mutate that value, which, in many cases, is not what you want as you will be mutating a copy. This is why you get a warning.
In this case, you can ignore it, but I would avoid mutable value types in general.
EDIT:
Let me attempt to simplify...
struct Point
{
int X;
int Y;
bool Mutate() { X++; Y++; }
}
class Foo
{
public readonly Point P;
Foo()
{
P = new Point();
P.Mutate(); // impure function on readonly value type
}
}
When Mutate() is called, a copy of P is created and passed along with the method. Any mutation of P's internal state will be irrelevant as it mutates a copy.
One of the conditions of a Pure Method is that its output (return value) is wholly dependent on its input (arguments).
Your .ToExactLocation() method is not pure, because its output depends both on the input arguments and also on the current value of a mutable struct.
Resharper doesn't like this, because mutable structs are bad (don't use them). I expect the error would go away if you either changed your code to use a class instead of a struct or redesigned the struct so the the .X and .Y members could only be set by the constructor.
Reading the answer, I found out that pure functions are necessarily like functions in mathematics. f(x) = x^2 + 2x + 10 will always return 10 if x is 0.
So ToExactLocation() must return the same values each time it is called, regardless changes to object since initial creation, for it to be called "pure".
There are 2 meaning of "pure function": one theoretical (no side effects/no dependency on mutable state) and another is what ReSharper thinks about functions.
From theoretical point of view your function is not pure because it depends on mutable state. Sample:
var someScreenLocation = new ScreenLocation(1,1);
var locationOne = someScreenLocation.ToExactLocation();
var locationTwo = someScreenLocation.ToExactLocation();
someScreenLocation.X = 3;
var locationThree = someScreenLocation.ToExactLocation();
For method to be pure it can change its result only based on input (not at all as in this case since there is no arguments). But you can clearly observe that locationOne and locationTwo are the same (good sign so far), but unfortunately locationThree is different even if the input (arguments to the function) still the same.
You can make it theoretically pure by making X and Y readonly (and adding constructor).
Even after the change ReSharper will still think it is not pure - to convince it you can use Pure attribute to mark it as pure.
Note that ReSharper marks usage of "impure" functions even in constructor of the class with readonly field. Sample below shows ReSharper warnings:
struct Point
{
public int X;
public int Y;
public Point(int x, int y){X = x;Y = y;}
public void Mutate(){X++;}
public Point TheoreticallyPure(){return new Point(1, 1);}
[Pure] public Point MarkedPure(){ return new Point(1, 1);}
}
class WithReadonlyField
{
public readonly Point P;
public WithReadonlyField()
{
P = new Point();
P.TheoreticallyPure(); // impure function on readonly value type
P.MarkedPure(); // return value of pure not used
P.Mutate(); // impure function on readonly value type - modifies P.
P = new Point().MarkedPure(); // ok to modify P multiple times.
}
public void NormalMethod()
{
P.Mutate(); // impure function on readonly value type, no changes to P
}
}
C# allows modification of readonly fields up to the end of constructor, but ReSharper marks usages of all "impure" functions there too (Note that Mutate function in constructor actually changes value of readonly field P, unlike in NormalMethod where it has no effect).
"readonly... assignments to the fields introduced by the declaration can only occur as part of the declaration or in a constructor in the same class"
Most likely this behavior of ReSharper is for consistency and to avoid cases where moving perfectly valid code changes behavior completely.
It would be better to model this as a static method (on either class) and would get rid of the impure warning. Explanation omitted, as the other answers covers the why already.
Example:
public static ExactLocation ToExactLocation(ScreenLocation loc)
{
return new ExactLocation {X = loc.X, Y = loc.Y};
}
or use an extension method
public static ExactLocation ToExactLocation(this ScreenLocation loc)
{
return new ExactLocation {X = loc.X, Y = loc.Y};
}
Not really sure about the cause, and I'd put this as a comment if it would format correctly...
Wouldn't you want something like:
var someScreenLocation = MethodThatGivesAScreenLocation();
if (DestinationLocation.X == someScreenLocation.ToExactLocation().X &&
DestinationLocation.Y == someScreenLocation.ToExactLocation().Y)
{
// Do stuff
}
I want to find the maximum value from the List objects.The class structure is
public class SiteData
{
#region Fields
private double? siteHeight;
private double? siteWidth;
#endregion
#region Properties
public double? SiteHeight
{
get { return siteHeight; }
set { siteHeight = value; }
}
public double? SiteWidth
{
get { return siteWidth; }
set { siteWidth = value; }
}
}
Now i am having the function to find the Maximum SiteHeight.The signature of the function is
public double FindMaxHeight(List<SiteData> objSite)
{
//logic to find the max. site height
}
I am using for loop to identify the maximum value and facing the performance issue....
.Net framework 2.0 - i am using right now
Can anyone tell me how to find the maximum height without using for loop? is it possible?
public class SiteData
{
private double? siteHeight;
private double? siteWidth;
public double? SiteHeight
{
get { return siteHeight; }
set { siteHeight = value; }
}
public double? SiteWidth
{
get { return siteWidth; }
set { siteWidth = value; }
}
public static double FindMaxHeight(List<SiteData> objSite)
{
objSite.Sort(delegate(SiteData s1, SiteData s2)
{
if (s1.SiteHeight > s2.SiteHeight)
return 1;
if (s1.SiteHeight < s2.SiteHeight)
return -1;
return 0;
});
return objSite[objSite.Count - 1].SiteHeight.Value;
}
}
With List T:
public static double FindMaxHeight<T>(List<T> objSite)
where T : SiteData
{
objSite.Sort(delegate(T s1, T s2)
{
if (s1.SiteHeight > s2.SiteHeight)
return 1;
if (s1.SiteHeight < s2.SiteHeight)
return -1;
return 0;
});
return objSite[objSite.Count - 1].SiteHeight.Value;
}
It's rather a strange way to do it, but you could do it with recursion.
You would create your initial function double FindMaxHeight(List<SiteData> objSite)
This would need to call a function that is a recursive function. A recursive function is one that causes itself to be called again, e.g.
int EnumerableLength(IEnumerable<T> enumerable)
{
IEnumerator<T> enumerator = enumerable.GetEnumerator();
return EnumeratorCount(enumertor, 0);
}
int EnumeratorCount(IEnumerator<T> enumerator, int count)
{
if(enumerator.MoveNext())
{
count++;
return EnumeratorCount(enumerator, count);
}
else
{
return count;
}
}
So you could move through your list like this, and comparing (enumerator.Current as SiteData).SiteHeight to the max height value you've currently got, and once you reach the end of the list you can return whatever the max is.
The simplest solution would be iterating over the list using a for loop and checking the individual entries for the maximum height.
Another possible solution would be to implement the IComparable interface and sort the list of all items according to its height. The first item in the list after the sorting is the one you are looking for.
For a more advanced solution you could also use the Find method on the specified list and specify a delegate that will determine the item with the maximum height.
Hope it helps.
As GregC said, the optimization depends on what your common case is. If the list is fairly static and does not have item added often, you can sort the list on insertion. This flips insertion from O(1) to the complexity of your sort algorithm (there are a number of O(n log n) algorithms) and retrieval from O(n) to O(1). How to use List<T>.Sort()
I prefer keeping it in a list as opposed to a dictionary because the dictionary method adds extra meaning to the hashcode that most people won't expect. Where as there are already built-in methods to sort a list that are standardized and many people will know immediately.
I'd add objects into a dictionary, that allows me to sort by height faster.
With all classic containers, there is a trade-off between rate of insertion and rate of retrieval.
This strategy makes sense when updates are rare, but you rely on the max value frequently.
You'd need to override GetHashCode() to return smaller numbers with larger heights.
I can see a little difficulty in that you'll have duplicates if your GetHashCode() is implemented that way. You'll need to decide on precision, and not insert duplicates into your collection based on that fact.
Alternately, I'd use MultiDictionary from PowerCollections, and then rely on linear search pattern for the few readouts that are in the topmost bin.
internal int IndexForSortingBySiteHeight
{
get
{
if(double.IsNaN(siteHeight) throw new ApplicationException();
return (int)Math.Floor(siteHeight);
}
}
public class ContainerForSortingBySiteHeight
{
private List<SiteData> siteDataItems;
public void Add(SiteData datum)
{
if(datum == null) return;
siteDataItems[datum.IndexForSortingBySiteHeight] = datum;
}
public Max
{
get { return siteDataItems[0]; } // here's why a list won't work! What index should i use?
}
}
you can use this Max method msdn Max
if this method doesn't present in 2.0 .Net I think is better to use for
It's not possible without loop if you have no kwnoledge about order of input sequence.
Show us your max value search code, maybe optimization is possible?
If you only want to skip the for you can use the following method:
public double FindMaxHeight(List<SiteData> objSite)
{
objSite.Sort(new Comparison<SiteData>((x, y) => y.SiteHeight.Value.CompareTo(x.SiteHeight.Value)));
return objSite.Count > 0 ? objSite[0].SiteHeight.Value : 0;
}
or this one if there can be SiteData withoud siteHeight value
public double FindMaxHeight(List<SiteData> objSite)
{
objSite.Sort(new Comparison<SiteData>((x, y)
=>
{
int xHeight, yHeight;
yHeight = y.SiteHeight.HasValue ? y.SiteHeight.Value : 0;
xHeight = x.SiteHeight.HasValue ? x.SiteHeight.Value : 0;
return yHeight.CompareTo(xHeight);
}
));
return objSite.Count > 0 ? objSite[0].SiteHeight.Value : 0;
}
but I don't know if it will have better performance that the for loop. I will crono them, but it will be nice to know, how big or at least the approximate number of SiteData that your list will have!