I am having the following class
public class MyDictionary : SortedList<int, MyData>
{
}
At the moment the Key in the SortedList represents a year number, e.g. 2014, 2015, 2016 etc. The Value represents the data for the year.
Now I have a new requirement saying that having a Value per year is not enough and this class should support a finer granularity.
The new granularity looks like this:
Yearly
Quarterly
Monthly
Weekly
Daily
Of course one instance of MyDictionary should represent one time frame, e.g. SortedList<Yearly, MyData>, SortedList<Monthly, MyData>.
The data that goes into MyDictionary spans over several years. That means that I cannot use, e.g. the number of a month in a monthly granularity. Example:
2014-12
2015-01
2015-02
...
2015-12
As you can see the number 12 is twice in the list.
My problem is, that I don't know what data type to use for the Key and how to access the Values in MyDictionary to meet the new requirement.
Any ideas?
Modification from 24.02.2016:
I must add a little more information to the original question.
The granularity is known at runtime only
The access to the Values via the array indexer [] must be runtime optimised. It will be called millions of times in a very short period of time.
The class that uses MyDictionary uses a DateTime object to access the Values. Example:
public class ClientClass
{
public void AccessMyDictionary(DateTime date)
{
MyData data = MyDictionary[date.Year];
// Do something with data
}
}
It looks to me that the most obvious thing to do is to have DateTime as an indexer data type. Then create an indexer in the MyDictionary class to take care of granularity. Example:
public enum Period
{
Yearly,
Quarterly,
Monthly,
Weekly,
Daily
}
public class MyDictionary
{
private Period period;
private SortedList<DateTime, MyData> sortedList;
public MyDictionary(Period period)
{
this.period = period;
sortedList = new SortedList<DateTime, MyData>();
}
public MyData this[DateTime i]
{
get
{
// Implement here an algorithm for granularity, similar to the one of Tomas Lycken in the 1st answer
}
set
{
// Implement here an algorithm for granularity, similar to the one of Tomas Lycken in the 1st answer
}
}
}
What do you think? Is that runtime optimised?
Many thanks
Konstantin
I would define some new value objects for the various granularities, all deriving from a common base class Period. You can then use as these keys. For example,
public abstract class Period { }
public class Quarter : Period
{
public int Quarter { get; }
public int Year { get; }
public Quarter(int year, int quarter)
{
if (year < 1800 || year > DateTime.UtcNow.Year)
{
throw new ArgumentOutOfRangeException(nameof(year));
}
if (quarter < 1 || quarter > 4)
{
throw new ArgumentOutOfRangeException(nameof(quarter));
}
Year = year;
Quarter = quarter;
}
}
And of course you'd define similar types for Year (which only has one property), Month (which has a year and a month, and the month must be between 1 and 12), Week (where validation becomes a little more tricky, since not all years have the same number of weeks), Day (don't forget to allow for leap years!).
Then, you also define equality and hashing for these types so that if their properties are equal, they are equal. (This is a good read on the topic!) For Quarter, I'd do something like
public class Quarter
{
// properties and constructor ommitted
public override bool Equals(object other)
{
if (!(other is Quarter))
{
return false;
}
var quarter = (Quarter)other;
return quarter.Year == Year && quarter.Quarter == quarter;
}
public override int GetHashCode()
{
unchecked // Overflow is fine, just wrap
{
// The two hard-coded digits below should be primes,
// uniquely chosen per type (so no two types you define
// use the same primes).
int hash = (int) 2166136261;
// Suitable nullity checks etc, of course :)
hash = hash * 16777619 ^ Quarter.GetHashCode();
hash = hash * 16777619 ^ Year.GetHashCode();
return hash;
}
}
}
Depending on how else you're going to use these, you might also want to override == and/or !=.
Now, these types are fully usable as keys in the dictionary, so you can do
var quarterlyReport = new SortedList<Quarter, Data>();
If you want to avoid having to define Equals and GetHashCode manually, most associative collections in .NET have a constructor which takes an equality comparer for the key type, that handles this for you. SortedList<TKey, TValue> has one too, so instead of overriding Equals and GetHashCode above you could create a pendant type for each period like
public class QuarterComparer : IComparer<Quarter>
{
int IComparer<Quarter>.Compare(Quarter p, Quarter q)
{
return p.Year < q.Year
? -1
: p.Year == q.Year
? p.Quarter < q.Quarter
? -1
: p.Quarter == q.Quarter
? 0
: 1
: 1;
}
public int Compare(Quarter p, Quarter q)
{
return (this as IComparer<Quarter>).Compare(p, q);
}
}
and pass this to the constructor of the sorted list:
var quarterlyData = new SortedList<Quarter, MyData>(new QuarterComparer());
Related
I have the following list I'm populating as I go through my class:
List<string> stringCollection = new List<string>();
I have a lot of static strings that I have declared before going to my class.
These strings are added to my list based on a collection of conditional expressions, meaning that it varies what kind of strings that I put into my list e.g.:
static string DescriptionText1 = "blabla",
DescriptionText2 = "blabla",
MagnitudeText1 = "blabla",
MagnitudeText2 = "blabla";
if(number < 2)
{
stringcollection.Add(DescriptionText1)
}
else
{
stringcollection.Add(DescriptionText2)
}
//Magnitude
if(magnitude > 128 && number < 256)
{
stringcollection.Add(MagnitudeText1)
}
else
{
stringcollection.Add(MagnitudeText2)
}
...
I then pass the list to my method in which I want to retrieve the strings like so:
public void Collection(List<string> ts)
{
string Description = ts.Find(DescriptionText); <--- my guess
string Magnitude = ts.Find(MagnitudeText);
}
How do I find the correct strings in my list, and write it to my newly declared strings in my method? - Even though they are appended hence 1,2,3 ... 6,7
Since you always put in Description first and then Magnitude, you can just do:
ts[0] // description
ts[1] // magnitude
Alternatively, consider writing a class that has the two properties:
// I don't know what these two things represent, please name it properly in your code!
class DescriptionMagnitude {
public string Description { get; }
public string Magnitude { get; }
public DescriptionMagnitude(string description, string magnitude) {
Description = description;
Magnitude = magnitude;
}
}
And then create an instance of this class and pass it around.
EDIT:
From your comment:
and then i would be able to search for my int variable?
It seems like you want to find the integer associated with the string. However, the 1 in DescriptionText1 is just part of an identifier. Why not just store the integer instead of the string?
Depending on what you are doing with the strings, an enum may be suitable:
enum Descriptions {
Foo = 0,
Bar = 1
Fizz = 2
}
In writing an insurance premium calculator the basic scheme is as follows: Points are assigned to a predetermined number of attributes, such as car-value, num-incidents-in-past, years-experience-driving etc. Hene, if car worth is $3800, that lies within the 3001 to 4000 range which warrants 30 points in the premium calculation. If num-incidents-in-past is 3 or below, that warrants ZERO points. If 4-5 num-inc then points warranted is 5. If years-exp is between 1-5, that warrants 12 points. The idea is an arbitrary value is being assigned to a range of values for any given number of attributes. The premium calculations is simply tallying up the points warranted for each attribute category and multiplying by some factor i.e 2.5. I am trying to use B. LISKOV'S power of abstractions AND the SRP to neatly assign responsiblities to design a calculator that is extensible and well designed.
Based on the answer provided by drharris here Is there a C# type for representing an integer Range?
How do I access the value out of the following Dictionary whose key is a generic type Range as defined by drharris?
//************************ABSTRACTIONS************************
public abstract class AbsPerson
{
public virtual AbsPolicy APolicy { get; set; }
public virtual string ID { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public virtual string Address { get; set; }
}
public abstract class AbsPolicy
{
public virtual string PersonID { get; set; } //FK
public virtual int PropValue { get; set; }
public virtual int InsGroup { get; set; }
}
public abstract class AbsValueCategoryCalculator: IEvaluatePolicy
{
//DATA
public abstract void InitRange();
//REFERENCE drharris poster GENERIC TYPE SIGNATURE - public class Range<T> where T : IComparable<T>
public abstract Dictionary<Range<int>, int> ValueRange {get; set;}
public abstract int Tally { get; set; }
//BEHAVIOUR
public virtual void EvaluatePolicyDetails(AbsPerson person)
{
}
}
public interface IEvaluatePolicy
{
void EvaluatePolicyDetails(AbsPerson person);
}
//*************************CONCRETIONS**************************
public class CarValueCategoryCalculator : AbsValueCategoryCalculator
{
public CarValueCategoryCalculator()
{//ctor
InitRange();
}
public override void InitRange()
{
this.ValueRange = new Dictionary<Range<int>, int>();
this.ValueRange.Add(new Range<int>() { Minimum = 1000, Maximum = 2000 }, 10);
this.ValueRange.Add(new Range<int>() { Minimum = 2001, Maximum = 3000 }, 20);
this.ValueRange.Add(new Range<int>() { Minimum = 3001, Maximum = 4000 }, 30);
this.ValueRange.Add(new Range<int>() { Minimum = 4001, Maximum = 5000 }, 40);
this.ValueRange.Add(new Range<int>() { Minimum = 5001, Maximum = 6000 }, 50);
this.ValueRange.Add(new Range<int>() { Minimum = 6001, Maximum = 7000 }, 60);
}
public override Dictionary<Range<int>, int> ValueRange
{
get; set;
}
public override void EvaluatePolicyDetails(AbsPerson person)
{
//I am trying to tally the value given wether the cars worth lies within the range
if (this.ValueRange.ContainsKey(new Range<int>() { Maximum = person.APolicy.PropValue, Minimum = person.APolicy.PropValue }))
{
this.Tally =
}
Console.WriteLine("good");
}
public override int Tally
{
get;set;
}
}//end class
(As noted in comments, Sam's answer points out that a dictionary isn't really what's wanted here - that only finds equal keys, whereas the OP is trying to find a range key that contains a single value. Hash tables just aren't geared up for that.)
You need to either override GetHashCode and Equals in Range<T> (which would be sensible - ideally implementing IEquatable<Range<T>> at the same time) or create a separate type which implements IEqualityComparer<Range<T>> and then pass that to the dictionary constructor.
I would probably do it on the range type, like this:
public sealed class Range<T> : IEquatable<Range<T>>
where T : IComparable<T>, IEquatable<T>
{
...
public override int GetHashCode()
{
int hash = 23;
hash = hash * 31 + EqualityComparer.Default<T>.GetHashCode(Minimum);
hash = hash * 31 + EqualityComparer.Default<T>.GetHashCode(Maximum);
return hash;
}
public override bool Equals(object other)
{
return Equals(other as Range<T>);
}
public bool Equals(Range<T> other)
{
if (ReferenceEquals(other, this))
{
return true;
}
if (ReferenceEquals(other, null))
{
return false;
}
return EqualityComparer<T>.Default.Equals(Minimum, other.Minimum) &&
EqualityComparer<T>.Default.Equals(Maximum, other.Maximum);
}
}
Note that currently the Range<T> type is mutable, however - that's generally a bad idea for dictionary keys. It would be a good idea to make it at least "shallow-immutable" - there's not a lot you can do if the
You'll either need to override Equals and GetHashCode on Range such that the items are compared based on the values you're interested in (min and max) rather than the default behavior (which is based on the object's reference).
If you cannot mutate the type (or don't want to) then you can create a type that implements IEqualityComparer<Range<T>>, implements the appropriate equals and hash generation methods, and then create an instance of that comparer that you pass to the dictionary.
I'm trying to read between the lines here, and I think that you are asking the wrong question.
This bit of code catches my eye (you may want to make it clearer so that others understand your need better):
public override void EvaluatePolicyDetails(AbsPerson person)
{
//I am trying to tally the value given wether the cars worth lies within the range
if (this.ValueRange.ContainsKey(new Range<int>() { Maximum = person.APolicy.PropValue, Minimum = person.APolicy.PropValue }))
{
this.Tally =
}
Console.WriteLine("good");
}
I think that what you are actually trying to do here is fetch the associated int value when person.APolicy.PropValue is within a Range.
What you are currently doing is wrong, and will not work, even if you add the proper Equals and GetHashCode overrides. Dictionaries only do exact matches. You are trying to do range matching.
Instead, I suggest you drop the dictionary in favor of a List of a new type composed of a Range and whatever that int value is. Then I would sort the list based on the Range's Minimum value. Then, you could optionally do a binary search in the list to quickly find candidate Range objects, and then use the Range.ContainsValue function to verify if person.APolicy.PropValue is within the range. Or, in this case, given that you only have a handful of Ranges, you can just iterate over the whole list and break out of the loop as soon as you find a Range that contains your value.
This is definitely a bit more work for you, but I think that this will get you what you are really looking for.
I am trying to sort an ArrayList using c#. When the ArrayList contains comparable objects, it is possible to sort with using list.Sort() but I need to sort an ArrayList which contains non-comparable objects. For example, let's say the object is Ring and it has an attribute property Price. Then I need to sort the ArrayList to the price order. If is is possible to select ascending or descending that will more helpful. Thank You!
Blockquote
arrAtdMon = **(ArrayList)**hashTb[unixMon];
if (arrAtdMon != null)
monCount = arrAtdMon.Count;
int[] arrayMax = { monCount, tueCount, wedCount, thuCount, friCount };
int maxValue = arrayMax.Max();
KidAttendance valMon = null;
string monTagName = string.Empty;
Blockquote
above array list is to be sorted it self.
You can do this by implementing IComparer interface:-
public class Ring : IComparer
{
public decimal Price { get; set; }
public int Compare(object x, object y)
{
return ((Ring)x).Price.CompareTo(((Ring)y).Price);
}
}
Working Fiddle.
First, you really should be using the List<T> class, not ArrayList. Doing so wouldn't solve your problem, but it would make the code less fragile and more easy to maintain.
As for the specific question, you want to do something like this…
Assume:
class Ring { public decimal Price { get; set; } }
Then:
ArrayList list = ...; // Initialized as some collection of Ring instances
list.Sort(Comparer.Create((r1, r2) => r1.Price.CompareTo(r2.Price)));
This creates a new Comparer instance using the Comparison<T> of (r1, r2) => r1.Price.CompareTo(r2.Price). That is, for each pair of objects being compared, compare the price of the first with the price of the second.
Assuming that these objects share a base class or an interface with the price property you should be able to do something like this:
// Base class with price property, could also be an shared interface
public abstract class Product
{
public decimal Price{get;set;}
}
public class Ring : Product
{
}
public class Bag : Product
{
}
// Some test data
var myUnsortedArray = new Product[]{new Ring{Price = 1.2m}, new Bag{Price=2.5m}};
// Easy sort with LINQ
var sortedProducts = myUnsortedArray.OrderBy(p => p.Price).ToArray();
var sortedProductsDescending = myUnsortedArray.OrderByDescending(p => p.Price).ToArray();
UPDATE
I just realised that the question is about ArrayLists and have the changed solution below:
// Some test data
var myUnsortedArrayList = new ArrayList{new Ring{Price = 1.2m}, new Bag{Price=2.5m}};
// Easy sort with LINQ
var sortedProducts = myUnsortedArrayList.OfType<Product>().OrderBy(p => p.Price).ToArray();
var sortedProductsDescending = myUnsortedArrayList.OfType<Product>().OrderByDescending(p => p.Price).ToArray();
To sort an set of objects, the object needs to be Comparable and you can set up the comparison you'd like in the CompareTo() method:
IComparable information here
I'm learning C# and currently we're looking into OOP concepts. We've been given this question and I'm struggling to understand some parts of it.
The gist of the question is this.
Define a class named Operator.
That class should implement following methods.
IsPositive - Receives an integer type value and returns true if it
is positive, false otherwise.
IsDayOfWeek - Receives a date time value and a week day name (E.g.
Saturday) and returns true if the value represents the given week day
name, false otherwise.
GetWords - Receives a text containing words (say paragraphs) and
returns a single dimension string array with all words. An empty
string array if there is no word available in the text.
It should be able to derive from Operator class and then create objects from the derived class.
Developers are allowed to use these methods from derived class for a given type. In other words, 1st method could be used when type = ‘N’ (number), 2nd methods could be used when type is ‘D’ (date) and 3rd method could be used when type is ‘S’ (string) given. Hence, the type should be provided when instantiating the object and it should be available throughout the class operations.
I have sufficient knowledge to write the methods but what I don't understand is the part I have bold-ed. What does it mean by some method can be used when some type is given and the type should be provided when instantiating the object and it should be available throughout the class? Are they talking about Properties?
I have given it a go. Below is my code.
public class Operator
{
private int _n;
private DateTime _d;
private string _s;
public DataProcessor(int n, DateTime d, string s)
{
this.N = n;
this.D = d;
this.S = s;
}
public int N
{
set { _n = value; }
}
public DateTime D
{
set { _d = value; }
}
public string S
{
set { _s = value; }
}
public bool IsPositive()
{
//method code goes here
return false;
}
public bool IsDayOfWeek()
{
//method code goes here
return false;
}
}
I'm not sure if I'm going the right way. Can somebody please shed some light on this?
This is how I read it:
public class Operator
{
public char TypeChar { get; set; }
public Operator(char operatorType) { this.TypeChar = operatorType; }
public bool IsPositive(int N)
{
if (TypeChar != 'N')
throw new Exception("Cannot call this method for this type of Operator");
// method implementation code
}
// same for the other methods
}
public NumericOperator : Operator
{
public NumericOperator() : base('N') {}
}
I want to store data such as
{
{"apple",15 }
{"pear",12.5 }
{"", 10 }
{"", 0.45 }
}
Data will be plotted on a bar chart (string will be the legend and double will be the value)
Insert order is important.
Perfs don't matter.
Strings could be duplicated or empty. (values could be duplicated too)
I need to get min and max values (easily if possible) to set the scale.
I use
List<KeyValuePair<string, double>> data = new List<KeyValuePair<string, double>>();
data.Add(new KeyValuePair<string,double>("",i));
Quite boring and unreadable.
Is there a cleaner way to do it ?
StringDoubleCollection data = new StringDoubleCollection();
data.add("apple",15);
data.add("",10);
double max = data.values.Max();
double min = data.values.Min();
if not how to get the max value of List<KeyValuePair<string, double>> without too much hassle
NameValueCollection looks nice but its a <string,string> I need a <string,double>
You could create a class like the following:
class X
{
public string Name { get; set; }
public double Value { get; set; }
// name is an optional parameter (this means it can be used only in C# 4)
public X(double value, string name = "")
{
this.Name = name;
this.Value = value;
}
// whatever
}
And then get maximum and minimum values using LINQ with a selector:
var data = new List<X>();
data.Add(new X(35.0, "Apple"))
data.Add(new X(50.0));
double max = data.Max(a => a.Value);
double min = data.Min(a => a.Value);
EDIT: if the code above still seems unreadable to you try to improve it using an operator for cases in which you want to have just the value.
// Inside X class...
public static implicit operator X(double d)
{
return new X(d);
}
// Somewhere else...
data.Add(50.0);
To determine which data structure you really want, lets look at your usage patterns.
Insert order matters.
You don't access your items by key.
You want min and max.
A heap offers min or max, but doesn't preserve order. A hash based dictionary also doesn't preserve order. A List is actually a good choice for your data structure. It is available and offers excellent support.
You can prettify your code by defining classes for both the data structure and your bar data. And you can add min/max functionality to the collection. Note: I didn't use the Linq Min/Max functions, because they return the minimum value, not the minimum element.
public class BarGraphData {
public string Legend { get; set; }
public double Value { get; set; }
}
public class BarGraphDataCollection : List<BarGraphData> {
// add necessary constructors, if any
public BarGraphData Min() {
BarGraphData min = null;
// finds the minmum item
// prefers the item with the lowest index
foreach (BarGraphData item in this) {
if ( min == null )
min = item;
else if ( item.Value < min.Value )
min = item;
}
if ( min == null )
throw new InvalidOperationException("The list is empty.");
return min;
}
public BarGraphData Max() {
// similar implementation as Min
}
}
Have you looked at LookUp?
The only problem is that it's immutable, so you need to be able to create your collection in one go.
As Anthony Pegram notes, it's a bit of a pain to create one. It depends on where your data is coming from. Have a look at the ToLookup method.
If it's worth it for usability (i.e. you're using awkward collections of List<KeyValuePair<string, double>> everywhere, it might just be worth it to implement StringDoubleCollection. It wouldn't be that difficult to wrap the underlying collection with the friendlier syntax you've described in your example.
And, as other comments / answers are suggesting, the Framework doesn't seem to provide a simpler solution that matches all of your requirements...
As for "max value", I assume you mean the Key-Value Pair with the greatest value. It can be retrieved like so:
var max = list.Select(kvp => kvp.Value).Max();
Just define your own model class to hold the data instead of depending on a KeyValuePair and everything becomes cleaner:
using System;
using System.Collections.Generic;
public class Fruit
{
public string Name {get; set;}
public double Price {get; set;}
}
public class Program
{
public static void Main()
{
List<Fruit> _myFruit = new List<Fruit>();
_myFruit.Add(new Fruit{Name="apple", Price=15 });
_myFruit.Add(new Fruit{Name="pear", Price=12.5 });
_myFruit.Add(new Fruit{Name="", Price=10 });
_myFruit.Add(new Fruit{Name="", Price=0.45 });
// etc...
}
}
What about implementing the StringDoubleCollection to work like you want...
public class StringDoubleCollection
{
private List<KeyValuePair<string, double>> myValues;
public List<double> values
{
get { return myValues.Select(keyValuePair => keyValuePair.Value).ToList(); }
}
public void add(string key, double value)
{
myValues.Add(new KeyValuePair<string,double>(key,value));
}
}
You can implementing Dictionary<key, value>
Dictionary<string, string> openWith = new Dictionary<string, string>();
openWith.Add("txt", "notepad.exe");
openWith.Add("bmp", "paint.exe");
openWith.Add("dib", "paint.exe");
openWith.Add("rtf", "wordpad.exe");
https://learn.microsoft.com/pt-br/dotnet/api/system.collections.generic.dictionary-2?view=net-5.0