Jagged dictionary of dynamic depth? - c#

I am trying to extract from a series of strings which represents depth like:
'foo/bar/x'
'foo/bar/baz/x'
'foo/bar/baz/x'
'foo/bar/lol/x'
Where x is a number I don't care about. I've got as far as splitting on the / and looping through, at which point in PHP I'd do something like check where in the loop I am (using for (i=0; etc)) and then use that to determine my depth to build an output array like:
output['foo']['bar'] = 1
output['foo']['bar']['baz'] = 2
output['foo']['bar']['lol'] = 1
The trouble is the 'depth' is dynamic and might be either just 3/4 deep (which I could just account for with lots of checks on the value of i and handling them separately) or say 10 or more deep in which case some kind of recursive function is probably best.
I've come across the issue that to have a string as an array index I need to use a dictionary, but you have to specify the types in the dictionary, meaning you need to know the depth in advanced (correct me if I'm wrong) when instantiating a dictionary object.
I guess an attack might be something like calling a recursive function such that each time it's called you pass i to indicate the depth, then the function calls itself decrementing i each time until it has built the portion of the tree from that input string but it's what storage structures I use for that in C# that I am not sure about.
The final output will be a CSV that I can open as a spreadsheet to look like:
Foo 0
|__Bar 1
|__Baz 2
|__Lol 1
Perhaps one direction for a solution is to use a pure C# Array and simply store the title (e.g. foo) in there, keeping information out of array indicies, which is probably best practice anyway. Thanks.

You can create your own class with following members:
class Directory
{
public int Value { get; set; }
public Dictionary<string, Directory> SubDirectories { get; set; }
}
Store your data using it and then recursively export it to CSV.
To get output["foo"]["bar"] syntax possible implement indexer within your class:
public Directory this[string name]
{
get { return SubDirectories.ContainsKey("name") ? SubDirectories[key] : null; }
set { SubDirectories.Add(name, value); }
}

While Marcin Juraszek solution is great, I just want to expand his answer just a little bit with dynamic sugar. It's not the fact, that this solution will fit your need, but just consider it as an example. I will make Directory<T> generic, so you can use whatever type for value (note that due to dynamic nature I have one cast in implementation (T)value)
class Directory<T> : DynamicObject
{
private T Value;
private Dictionary<string, Directory<T>> SubDirectories;
public Directory()
{
SubDirectories = new Dictionary<string, Directory<T>>();
}
public override bool TryGetMember(GetMemberBinder binder, out Object result)
{
if (!SubDirectories.ContainsKey(binder.Name))
SubDirectories[binder.Name] = new Directory<T>();
result = SubDirectories[binder.Name];
return true;
}
public override bool TrySetMember(SetMemberBinder binder, Object value)
{
if (!SubDirectories.ContainsKey(binder.Name))
SubDirectories[binder.Name] = new Directory<T>();
SubDirectories[binder.Name].Value = (T)value;
return true;
}
public override string ToString()
{
return Value.ToString();
}
}
And now you can use dynamic feature, available from C# 4.0
dynamic dir = new Directory<string>();
dir.foo = "Foo Value";
dir.foo.bar = "Bar Value";
dir.foo.bar.baz = "baz value";
dir.foo.bar.Lol = "Lol value";
Console.WriteLine(dir.foo.bar.Lol); //will print Lol value
Console.WriteLine(dir.foo.bar.baz); //will print baz value
which is:
Foo Foo Value
|__Bar Bar Value
|__Baz baz value
|__Lol Lol value
you can also override TryGetIndex and TrySetIndex so that you can pass complex strings, which can't be used as properties in C#

Related

How can you get the String values from an array of objects?

I have some code that basically checks the list of queues a current business object has been through. These queues are kept in an array aptly named _queueNames of type IKeyMap, a custom object my company uses.
I would like to get the textual names of the queues, as I need to check for the presence of a particular keyword and handle it separately if it's hit that particular queue.
I was hoping I could just do something like this;
var queues = _queueNames.ToArray().ToString();
if (queues.Contains("Condition"))
DoSomethingElse();
but that just gives me the object type, rather than a collection of the values. Looking at the KeyMap object, looks like just a simple key/value pair, might there be another way to do this?
Edit: KeyMap class & interface:
public interface IKeyMap : IDisposable
{
string Ley {get;}
string Field {get;}
}
public class KeyMap : IKeyMap
{
string _key, field;
public KeyMap(string key, string field)
{
_key = key;
_field = field;
}
public override string ToString()
{
return string.Format("{0}_{1}", Key, Field);
}
public string Key { get {return _key; } }
public string Field { get {return _field; } }
}
I left out some overrides, such as hashing & the Dispose method since I've got to manually type this out, can't copy-paste from my remote session :(
Without knowing what the objects inside of _queueNames look like, there is no exact answer. One mistake being made here is that you are checking a single string representing an entire array. What you want to do is check every object in the array for some value, or convert it to a string and check that value.
Here is an example:
foreach (var item in array)
{
if (item.ToString().Contains("Condition"))
{
DoSomethingElse();
break;
}
}
Or the LINQ way:
if (array.Any(item => item.ToString().Contains("Condition")))
DoSomethingElse();
This specific example only works if the object can be converted into a string that is useful to parse. You could also be accessing a member or invoking a function on said object to get your string. We can't know without more information, but hopefully this points you in the right direction.
In your IKeyMap interface, let's add a Boolean.
public string IsSpecial { get; set; }
When you create the object, set the IsSpecial flag. Then read it later..
var queues = _queueNames.ToArray().ToString();
if (queues.IsSpecial)
DoSomethingElse();
This avoids searching for strings, which is something you want to avoid. What if one of the other queues accidently end up with that string? Or what if you change the special string in one place but forget to change it in another? Or what if the capitalization is different? Or what if the string ends up with a special character that you can't see in it?
And even better way would be with an enum instead of Boolean.
public HandleType QueueHandleType {get;set;}
public enum HandleType {Normal, Special, SuperSpecial}
I might be misreading this, but is there any reason you can't just store the queues by name in array of Key/Value pairs, or even a Dictionary? For example:
var queues = new Dictionary<string, object>();
// add your queues to the dictionary, with the key name being your queue name
queues.Add("Queue1", myQueue);
// etc.
At that point you have a couple of options. First, you don't need to loop through the total set of queues you have -- you can simply do this:
var specialQueue = queues[mySpecialQueueString];
// do something with it
Or you can use LINQ to get any queues whose name contains your special string:
var results = queues.Where(keyValuePair => keyValuePair.Key.Contains(mySpecialString)).ToArray();
That said, Mason has a point in that you might need to worry about string matching and the like. There are, of course, several ways to go about this. If all queues have a fixed name then I like to make a NameConstants class with a bunch of static strings and refer to members of that class. Or you can do things like making them all upper and comparing to that.

Indexers and storage location

one of the restrictions on Indexers is that indexer does not define a storage location, So a value produced by an indexer cannot be passed as a ref or out parameter to a method.
I was wondering the array that we define for indexer isn't a storage location?
I am going to break down each part of your question and try to help you out.
Does Index Define a Location in Storage?
one of the restrictions on Indexers is that indexer does not define a storage location
If saying is "a location somewhere in storage is not guaranteed to be abstractedly defined in the classes implementation of that index" then yes that is correct, abstractly you are defining a value at the Index of the value of your indexer, but that does not guarantee you are accessing a logical location (at an abstract level, at a low level everything has a location). Basically an index is a pretty way to represent a method that takes a value and returns a value a variable(s) that indicates location and using syntax of brackets, and the equal sign to determine which method to call (get or set). I feel like I am getting off topic but you can look up more info on index implementation on on MSDN. But just like methods you have to make it make sense. Here is an example of failing at that making sense and also not having an actual location on the back end of the implementation.
A Weird Example
public class MyClass
{
private void Set(int i,string value)
{
Console.WriteLine("Your Index:{0}\r\nSet Value:{1}",i,value);
}
public string this[int i]
{
get
{
if(i<0)
return "less than zero";
if(i==0)
return "This is zero";
else if(i==1)
return "This is one";
else if(i==2)
return "this is two";
else
return "more than two";
}
set
{
//value is a key word in a setter
//representing the value on you are attempting to set
Set(i,value);
}
}
}
Don't do this
Why you would want to do this I am not sure sure, but if you did want to you could, indexers are just a nice way of expressing a method where it makes sense that it is acting as an index, such as in a Dictionary or a List, and while someone might try to argue that technically the getter in this example does it still makes no sense and shouldn't be using an index to express the method
Can You Pass an Index by ref or out to a Method
So a value produced by an indexer cannot be passed as a ref or out parameter to a method.
since the data you are accessing through the index is encapsulated in the class unless the class exposes a reference to that data you cannot accesses it, therefore you cannot use pass it as a ref or an out parameter in a method call for an indexer property, so we need to see if accessing the indexer exposes a location in memory
Short Answer
No, the key words `ref` and `out` basically tell the IL to make the method take a memory address, `out` requiring the location in memory be assigned a new value, `ref` not requiring a change but still allowing it to happen, since all indexes and properties are not supported in all languages in .NET they are implemented by changing the instructions in "get" and "set" into method calls, `ref` and `out` needs a location in memory of the passed variable, reduced to IL trying to treat a get/set of an indexer as an out variable is equivalent to trying to treat a method or a fresh variable as a `ref` or `out` parameter which is semantically invalid
Long Answer
You cannot, the reason why is because you are calling a method when you use the indexer, say you have this as the method you want to a call
public void CreateNew(out object target)
{
target = new object();
}
What is happening
When you call the CreateNew method at some level instructions:
Take CreateNew Instruction Location
Puts The Location of the variable passed to target into a parameter slot
Changes the value of the memory in the location to a place in the heap
holding the object created by the "new object();" statement
Returns control
It Doesn't work with an indexer
An indexer is called in two cases
Get:
the indexer "Get" method appears where the object is indexed and is trying to be accessed. When this happens a method call is made to some method that represents your get method that has a signature like
ValueType _get_index_IndexType_ValueType( IndexType index)
so if the compiler resolved your call to this as the out parameter then it would be like trying to pass a reference to a variable that hasn't been assigned a location in memory yet. That is why it wouldn't work with the "Get" method and this was done by design as logically you cannot access a location in memory for a variable from the location in memory of an object.
Set:
The indexer "Set" method appears when the object is indexed and on the left hand side of an equal sign, internally it is replace with some method that represents your set method that has a signature like this
void _set_index_IndexType_ValueType(IndexType index, ValueType Value)
So if the call reduces to this it would be the same thing as trying to access the location in memory of a method call, this is not what we want, what we want to do is call the set method when giving a new variable to the index, and get when we are trying to access it. However by design this is not allowed, as you can easily do this on your own...
More Code
If this still doesn't make sense try thinking of the class below, where instead of having an indexer method we just use a Get and Set with an index
public class MyFooIndexableObject
{
/* Note that "ValueType" and "IndexType" are
* just place holders for whatever type you
* decide to make as your return type and
* index type respectively
*
* Using a regular dictionary and an
* extra variable to implement a default
* dictionary so it is not like the example
* is doing nothing.
*/
private Dictionary _internalCollection;
private readonly ValueType _defaultValue = new ValueType();
public void FooSet(IndexType index, ValueType value)
{
if( index == null)
//want to disallow index being null
throw new NullArgumentException("index");
if(_internalCollection==null)
_internalCollection = new Dictionary();
if ( value == null || value == _defaultValue )
// want to remove it
{
_internalCollection.Remove(index);
}
else
_internalCollection[index]=value;
}
/* The Examples FooSet and FooGet
* would be similar method constructs to
* the ones made behind the scenes when
* you define the getter and setter for
* your indexed object
*/
public ValueType FooGet(IndexType index)
{
if( _internalCollection == null
|| !_internalCollection.Contains(index) )
return new _defaultValue;
return _internalCollection[index];
}
public bool TryGetValueAtFirstNonDefault(out IndexType outIndex,
out ValueType outValue)
{
outParam = outIndex = null;
if(_internalCollection!=null)
{
// no need to check we maintain this in the setter and getter
var temp= _internalCollection.FirstOrDefault();
if(temp!=null)
{
outParam = temp.Value;
outIndex = temp.Key;
}
}
return outParam != null;
}
private static void Swap( ref ValueType someRefParam,
ref ValueType otherRefParam)
{
var temp = someRefParam;
someRefParam = otherRefParam;
otherRefParam = temp;
}
//use this instead
public void SwapValueAtIndexes(IndexType index1, IndexType index2)
{
var temp = this.FooGet(index1);
this.FooSet(index1, this.FooGet(index2) );
this.FooSet(index2, temp);
}
public static void Main(string[] args)
{
var indexable = new MyFooIndexableObject();
var index1 = new IndexType(0);
var index2 = new IndexType(1);
ValueType someValue;
//do someValue = indexable[index1]
someValue = indexable.FooGet(index1);
//do indexable[index1] = new ValueType()
indexable.FooSet(index1,new ValueType());
//this does not make sense will not work
//do Swap( out indexable[index1], out indexable[index2] )
//just look how you would try to do this
Swap( ref indexable.FooGet(index1), ref indexable.FooGet(index2));
//Swap is looking for reference to a location in memory
//but the method is returning the value of an object reference
//which you can store in a variable with a location in memory
//but has yet been assigned to one
//Please note the whole idea of "location in memory" is abstract
//it does not technically mean an actual location in physical
//memory but probably an abstraction handled by .NET,
//don't try to hard to make sure you have the technical part
//100% correct, you are significantly detached from the metal
//when coding at this level...the basic idea is the same
//as physical memory locations on a machine
//However, you can accomplish the same things that you would
//want to accomplish with "out" and "ref" by creating methods
//that take the indexed object and an index, such as the
//SwapValueAtIndex method
indexable.SwapValueAtIndex(index1,index2);
//While precisely what SwapValueAtIndex does may
//not translate to what Swap does logically
//it is the same thing, which is good enough for us
}
}
But You Can...
Even though you can't get to the actual reference of the object you can pass the index and the indexed object to a method, this will effectively give you the same effect as a reference to the variable because you can access it using the index and the object that it is located in
public void Swap(MyIndexedObject o, string indexer, object newValue,
ref object oldValue)
{
if(o.Contains(indexer))
{
oldValue = o[indexer];
}
else
oldValue = null;
o[indexer]=newValue;
}
public bool TryGetValue(MyIndexedObject o, string index, out object value)
{
value=null;
if(o.Contains(index))
{
value = o[value];
return true;
}
return false;
}
public void TrySwapValue(MyIndexedObject o, string indexer1, string indexer2)
{
object valHolder1=null,valHolder2=null;
if(TryGetValue(o,indexer1, out valHolder1))
{
Swap(o, indexer2, valHolder1,ref valHolder2);
o[indexer1] = valHolder2;
}
}
What that Means
As you can see you can logically use an index as a location (in a case where the indexed object implementation makes sense) if you have the object, that is where indexed objects make sense to use
Other Options
If you still want a reference to an indexed object you can define a class that has an index and gets and sets the value of the object, in this you could include thing like a history
public class MyObject : Dictionary{}
public class MyPlaceHolder
{
public MyPlaceHolder(string index, MyObject target)
{
Index = index;
TargetObject = target;
}
public string Index {get; private set;}
public MyObject TargetObject {get; private set;}
public object Value
{
get
{
return TargetObject[Index];
}
set
{
var prev = TargetObject[Index];
TargetObject[Index] = value;
_prevVals.Push(prev);
}
}
private Stack _prevVals = new Stack();
public bool UndoSet()
{
if(!_preVals.Count() == 0)
{
Value._prevVals.Pop();
return true;
}
return false;
}
}
Is a Storage Location in Existence for an Index?
I was wondering the array that we define for indexer isn't a storage location?
Yes that array is a location, but the index definition is not a direct reflection of that address. An index into an object is an abstraction of the the concept of an Index, which is something that allows you to access an object based on an index value you pass into it, it does not necessarily do that but it should, technically it could be a method that has nothing to do with a location but it shouldn't.
However the way the object does not expose the actual location underneath is correct, you are using encapsulation to hide the way the location specified by your index method, which is one of the reasons we have object oriented programming I don't care if 0 is a location at the level of the implementation as long as it makes sense when I use it
A Better Example of using an Index
I feel bad for only creating one example of an Indexed object that is actually awful and something hopefully no one ever mistakenly thinks is a good idea, so will show why it makes sense to hide location, this is the purpose behind the abstraction of an index
Let's say I want to make a double key dictionary, I know in some part of my code I am going to implement it, but I don't know how yet, if you have multiple people working so you don't want people to wait around while you code the class, so you can define the interface, and implement it while the other programmers work
public interface IMyDoubleStringDictionaryBase<T>
{
T this[string index1, string value2]
{
get;set;
}
}
The First Implementation
You decide to make it using nested dictionaries, this is what you come up with
public class MyDoubleStringDictionary<T> : IMyDoubleStringDictionaryBase<T>
{
private Dictionary<string,Dictionary<string,T>> _baseCollection;
public T this[string index1, string index2]
{
get
{
if(_baseCollection.ContainsKey(index1))
{
var nextDict = _baseCollection[index1];
if(nextDict.ContainsKey(index2))
{
return nextDict[index2];
}
}
return default(T);
}
set
{
Dictionary<string,T> nextDict;
if(_baseCollection.Contains(index1))
{
nextDict = _baseCollection[index1];
}
else
{
nextDict = new Dictionary<string,T>();
_baseCollection.Add(index1,nextDict);
}
nextDict[index2] = value;
}
}
}
You Have a Problem
For some reason the Dictionary class is not available to you in your production environment, while this might not make sense to you you are told to make one using only the Array data structure, all other abstract data structures you need to define yourself. You decide to make a bucket hash that takes the two hashes of the keys and mixes them
public class MyNewDoubleStringDictionary<T> : IMyDoubleStringDictionaryBase<T>
{
private class Node<T>
{
public Node<T> Next;
public string Key1,Key2;
public T Value;
}
private const int ARRAY_SIZE = 1024;
private Node<T>[] _internalCollection = new Node<T>[ARRAY_SIZE];
private int GetIndex(string key1, string key2)
{
const int key1mask = 0x0F0F0F0F;
const int key2mask = 0xF0F0F0F0;
var key1 = key1mask & key1.GetHashCode();
var key2 = key2mask & key2.GetHashCode();
var result = ((key1 | key2) & 0x7FFFFFFF)% ARRAY_SIZE;
return result;
}
private Node<T> GetOrMakeNode(string key1,string key2)
{
int index = GetIndex(key1,key2);
Node<T> currNode=_internalCollection[index];
if(currNode == null)
{
_internalCollection[index] = currNode = new Node<T>();
}
else
{
while(!(currNode.Key1.Equals(key1)
&&currNode.Key2.Equals(key2))
if(currNode.Next!=null)
{
currNode = currNode.Next;
}
else
{
currNode.Next = new Node<T>();
currNode = currNode.Next;
}
}
if(currNode.Key1 == null || currNode.Key2 == null)
{
currNode.Key1 = key1;
currNode.Key2 = key2;
}
return currNode;
}
public this[string index1, string index2]
{
get
{
var node = GetOrMakeNode(index1,index2);
return node.Value;
}
set
{
var node = GetOrMakeNode(index1,index2);
node.Value = value;
}
}
}
The Result
Even though you had a change in requirements and implementation it did not interrupt any of your team's work, because you aren't making references to internal workings of objects so it would be impossible for it to mess up their work.
Why it Makes Sense
You don't care where the location is, you shouldn't really be worried if the actual implementation is looking at a location just know that you have to interface the index in a certain way and you will be able to use it
http://msdn.microsoft.com/en-us/library/vstudio/6x16t2tx.aspx
Indexer are just special getters and setters. And ref or out are always just local variables. Indexer doesn't even have to point to a storage location but can return computed values.
Indexer don't even have to be used on arrays. For example in a vector image i could define indexers myvectorimage[x][y] such that it returns the color at a x and y location but the data is never stored that way.

How can I avoid ref parameters?

I have a method that has 2 ref parameters:
public void ReplaceSomething(ref int code, ref string name)
{
...
}
I want to avoid this, as it is not a good design (and scales poorly). What are my options?
I've though about using an anonymous object, but that doesn't seem like a good idea, either.
Object something = new { code = 1, name = "test" };
ReplaceSomething(something);
Are the code and the name closely linked together? If so, consider creating a type to put the two of them together. Then you can return a value of that type.
Alternatively, you might consider returning a Tuple<int, string>.
(In both cases you can accept an input parameter of the same type, of course. As you haven't shown any of your code, it's not really clear whether you use the existing values of the parameters, or whether they could basically be out parameters.)
Why don't you want to use ref arguments? That seems like a perfectly good way to change some caller values.
The other approach would be to implement a return value. Maybe you need to better explain what the problem is?
If these values are tightly coupled and "belong together" you could define a custom class that holds your properties and either return a new instance (assuming its immutable) of that or update its properties:
class Code
{
public int Value {get;set;}
public string Name {get;set;}
}
public Code UpdateCode(Code code)
{
...
}
If you need to return these values, you can either use a tuple
public Tuple<int, string> ReplaceSomething(int code, string name)
{
...
}
Or create your own class-wrapper that holds the values as properties
public Foo ReplaceSomething(int code, string name)
{
var foo = new Foo(){...};
return foo;
}
class Foo
{
public int IntValue{get;set;}
public string StringValue{get;set;}
}
Why would you change it? ref parameters make sense at times, and if this is one of those times - use them. You could introduce a new class that contains that pair of values, which only makes sense if those values come together often.
I say, keep it.
Based on your question, I could be way off. What do you mean by replacing ref? Are you looking to overload?
public void ReplaceSomething(int code, string name)
{
// ...
}
public void ReplaceSomething()
{
return ReplaceSomething(1, "test");
}
Edit:
ok, so you need to return the code and the name what are the calculations that need to be made? Jon Skeet's answer about a tuple could be right, or you might need a POCO that contains the code the name and the replaced
public void ReplaceSomething(int code, string name)
{
var replaced = new Replaced();
replaced.code = code;
replaced.name = name;
var r;
// do some replacement calculations
replaced.replaced = r;
return replaced;
}
public class Replaced {
public string name {get; set;}
public int code {get; set;}
public string replaced {get; set;}
}

Use of pointer like structure in C#

We are transfering our code from C++ to C# and due to limited knowledge of C# we are stuck into strange situation. Our problem is:
In c++ we have 2-3 types of class/structures which have pointers to property (std::string), purpose of pointer is to make sure that all the instance for similar object will point to same property. e.g
struct st1{
string strVal;
};
struct st2{
string* strVal;
};
//At time of creation
st1* objst1 = new st1();
st2* objst2 = new st2();
objst2.strVal = &objst1.strVal;
//After this at all point both object will point to same value.
I want this kind of architecture C#, I got some suggestion like:
Declare events
Make code unsafe and use pointers (but I think this will lead to some other problems)
Please let me know if something better and near to C++ can be done here..
In C# all clases are references / pointers. So as long as your property is of class type, you can have same instance in different structures.
But problem can arise when you use string. While it is class and reference property, it is enforced to be imutable. So when you change it, you dont change the instance itself, but you create new copy with those changes.
One solution that comes to mind is to create custom string class, that will simply contain string and use it as your type:
public class ReferenceString
{
public String Value { get; set; }
}
You could use a static property with inheritance:
class thing
{
static string stringThing;
public string StringThing
{
get { return stringThing; }
set { stringThing = value; }
}
}
class thing2 : thing
{
}
Then later:
thing theThing = new thing();
theThing.StringThing = "hello";
thing2 theThing2 = new thing2();
// theThing2.StringThing is "hello"

How to use Comparer for a HashSet

As a result of another question I asked here I want to use a HashSet for my objects
I will create objects containing a string and a reference to its owner.
public class Synonym
{
private string name;
private Stock owner;
public Stock(string NameSynonym, Stock stock)
{
name=NameSynonym;
owner=stock
}
// [+ 'get' for 'name' and 'owner']
}
I understand I need a comparer , but never used it before. Should I create a separate class? like:
public class SynonymComparer : IComparer<Synonym>
{
public int Compare(Synonym One, Synonym Two)
{ // Should I test if 'One == null' or 'Two == null' ????
return String.Compare(One.Name, Two.Name, true); // Caseinsesitive
}
}
I prefer to have a function (or nested class [maybe a singleton?] if required) being PART of class Synonym instead of another (independent) class. Is this possible?
About usage:
As i never used this kind of thing before I suppose I must write a Find(string NameSynonym) function inside class Synonym, but how should I do that?
public class SynonymManager
{
private HashSet<SynonymComparer<Synonym>> ListOfSynonyms;
public SynonymManager()
{
ListOfSymnonyms = new HashSet<SynonymComparer<Synonym>>();
}
public void SomeFunction()
{ // Just a function to add 2 sysnonyms to 1 stock
Stock stock = GetStock("General Motors");
Synonym otherName = new Synonym("GM", stock);
ListOfSynonyms.Add(otherName);
Synonym otherName = new Synonym("Gen. Motors", stock);
ListOfSynonyms.Add(otherName);
}
public Synonym Find(string NameSynomym)
{
return ListOfSynonyms.??????(NameSynonym);
}
}
In the code above I don't know how to implement the 'Find' method. How should i do that?
Any help will be appreciated
(PS If my ideas about how it should be implemented are completely wrong let me know and tell me how to implement)
A HashSet doesn't need a IComparer<T> - it needs an IEqualityComparer<T>, such as
public class SynonymComparer : IEqualityComparer<Synonym>
{
public bool Equals(Synonym one, Synonym two)
{
// Adjust according to requirements.
return StringComparer.InvariantCultureIgnoreCase
.Equals(one.Name, two.Name);
}
public int GetHashCode(Synonym item)
{
return StringComparer.InvariantCultureIgnoreCase
.GetHashCode(item.Name);
}
}
However, your current code only compiles because you're creating a set of comparers rather than a set of synonyms.
Furthermore, I don't think you really want a set at all. It seems to me that you want a dictionary or a lookup so that you can find the synonyms for a given name:
public class SynonymManager
{
private readonly IDictionary<string, Synonym> synonyms = new
Dictionary<string, Synonym>();
private void Add(Synonym synonym)
{
// This will overwrite any existing synonym with the same name.
synonyms[synonym.Name] = synonym;
}
public void SomeFunction()
{
// Just a function to add 2 synonyms to 1 stock.
Stock stock = GetStock("General Motors");
Synonym otherName = new Synonym("GM", stock);
Add(otherName);
ListOfSynonyms.Add(otherName);
otherName = new Synonym("Gen. Motors", stock);
Add(otherName);
}
public Synonym Find(string nameSynonym)
{
// This will throw an exception if you don't have
// a synonym of the right name. Do you want that?
return synonyms[nameSynonym];
}
}
Note that there are some questions in the code above, about how you want it to behave in various cases. You need to work out exactly what you want it to do.
EDIT: If you want to be able to store multiple stocks for a single synonym, you effectively want a Lookup<string, Stock> - but that's immutable. You're probably best storing a Dictionary<string, List<Stock>>; a list of stocks for each string.
In terms of not throwing an error from Find, you should look at Dictionary.TryGetValue which doesn't throw an exception if the key isn't found (and also returns whether or not the key was found); the mapped value is "returned" in an out parameter.
Wouldn't it be more reasonable to scrap the Synonym class entirely and have list of synonyms to be a Dictonary (or, if there is such a thing, HashDictionary) of strings?
(I'm not very familiar with C# types, but I hope this conveys general idea)
The answer I recommend (edited, now respects the case):
IDictionary<string, Stock>> ListOfSynonyms = new Dictionary<string,Stock>>();
IDictionary<string, string>> ListOfSynForms = new Dictionary<string,string>>();
class Stock
{
...
Stock addSynonym(String syn)
{
ListOfSynForms[syn.ToUpper()] = syn;
return ListOfSynonyms[syn.ToUpper()] = this;
}
Array findSynonyms()
{
return ListOfSynonyms.findKeysFromValue(this).map(x => ListOfSynForms[x]);
}
}
...
GetStock("General Motors").addSynonym('GM').addSynonym('Gen. Motors');
...
try
{
... ListOfSynonyms[synonym].name ...
}
catch (OutOfBounds e)
{
...
}
...
// output everything that is synonymous to GM. This is mix of C# and Python
... GetStock('General Motors').findSynonyms()
// test if there is a synonym
if (input in ListOfSynonyms)
{
...
}
You can always use LINQ to do the lookup:
public Synonym Find(string NameSynomym)
{
return ListOfSynonyms.SingleOrDefault(x => x.Name == NameSynomym);
}
But, have you considered using a Dictionary instead, I believe it is better suited for extracting single members, and you can still guarantee that there are no duplicates based on the key you choose.
I am not sure that lookup time is of SingleOrDefault, but I am pretty sure it is linear (O(n)), so if lookup time is important to you, a Dictionary will provide you with O(1) lookup time.

Categories

Resources