I am pretty new to this so forgive my noobishness here.
I am trying to edit an item in a c# sortedset if I find that the item exists. So I can use list.contains(value) and find that the value does exist in the list. But how do I get that item out of the list. Here is what I have. This gets really slow as my list size gets really big, so I'm guessing there must be a better way than this.
if (list.Contains(p))
{
Person exists = list.First(person => person.Name.Equals(line[0]));
// do something here to exists
}
else
{
// just add the person to the list
}
As of .NET Framework 4.7.2 there is TryGetValue method available for SortedSet.
For the .NET Frameworks older than the version 4.7.2:
It is not possible to get an element from SortedSet or HashSet collections (using the Contains method or somehow else). One can just get to know whether the collection contains the element. Since in order to find this element in the collection, one already uses this element (passing it to the Contains method), it can be assumed that one already has this element.
For the .NET Frameworks starting from the version 4.7.2:
See this answer.
Do you really need SortedSet which is red-black tree? If you don't need sorting, you shouldn't use it. Have you considered HashSet or Dictionary instead which is more suitable (fast) for getting item by key?
In your case you probably need to create Dictionary instance with key equals to person name, i.e.:
Dictionary<string, Person> list;
Then you can get person by it's name, complexity is O(1)
if(list.ContainsKey(line[0]))
{
list[line[0]]...
}
or even better:
Person p;
if(list.TryGetValue(line[0], out p))
{
p...
)
You may want to consider using the PowerCollections project — it has a lot of useful improvements to the standard generic collections.
Related
How can I find all items in a sorted collection?
Basically I have a List<T> collection (large one). First I want to sort it so that the subsequent calls for finding all matches could be performed as fast as possible. i would like to use some build-in mechanisms rather than performing manual searches.
I initially used FindAll but that probably will enumerate the entire collection and I need to speed it up.
It has to be done under .NET 2.0
EDIT
I have a collection: List<Custom>
Custom is a class with 3 public fields (it is a container)
Then I sort it:
collection.Sort((x, y) => x.Id.CompareTo(y.Id)); // Id is a Guid
Now I need to find all items in a collection by Id without
enumerating all items in a collection.
IEqualityComparer<T> and IEquatable<T> interfaces have been available since .NET 2.0 and this framework version introduced generic dictionaries: Dictionary<TKey, TValue>.
What you can do is indexing. For example, if you want to get your objects by id in a constant time, in addition to adding them to your list, you can add them to a Dictionary<Guid, Custom>.
Now you can get objects by id in a constant time:
Custom custom = all[someGuid];
This approach can be followed by the rest of your class properties.
Why I've talked about IEqualityComparer<T> and IEquatable<T>? Because if one of the whole properties is another custom class, maybe you'll need to implement one of the so-called interfaces (and/or override Object.Equals and Object.GetHashCode) to implement a custom equality, so dictionary keys will be unique.
If you want to combine more than a property, maybe you'll need to define a class to provide one or more properties:
public class Args
{
public CustomA CustomA;
public CustomB CustomB;
}
...and you can implement an IEqualityComparer<T> for Args to provide a combined hash code and be able to use Args as dictionary key. This would be like looking for an object which matches all provided properties in a given Args instance... (i.e. like using an && operator in a where clause...).
Did you try Sort from the Collections namespace? Try providing a Comparer.
List.Sort Method () .NET Framework 2.0
Why not use a 2D array instead of sorted list, where the first dimension is the GUIDs?
OR
Sort the list, use IndexOf to get the first index of your GUID. Then, use RemoveRange to remove all items before the index you got. And lastly, use Find on the remaining range to get the first GUID that doesn't match your GUID.
See here: LINQ support on .NET 2.0
The easiest way I can think of is to use Linq:
wrong way
List<Order> objListOrder = new List<Order>();
GetOrderList(objListOrder); // fill list of orders
Right way
List<Order> SortedList = objListOrder.OrderBy(o=>o.OrderDate).ToList();
Use LINQ with .NET Framework 2.0
LINQBridge (from the author of the excellent LINQPad) is a small 60KB assembly that when combined with the multi-targeting capabilities of Visual Studio 2008 gives the ability to write code which does LINQ to Objects (not XML or SQL) but runs fine on a machine with just the .NET Framework 2.0 installed. Very clever
For the purpose of XML serialisation I had to disband a Dictionary collection I was using. I wrote a very straightforward alternative which consists of 2 classes:
NameValueItem: contains Name (Key) and Value
NameValueCollection: derived from CollectionBase and maintains a collection of NameValueItem objects.
I've included some standard methods to help maintain the collection (Add, Contains and Remove). So just like most Dictionary types, the Name (or Key) is unique:
public bool Contains(NameValueItem item)
{
foreach (NameValueItem lItem in List)
if(lItem.Name.Equals(item.Name))
return true;
return false;
}
Add uses this Contains method to determine whether to include a given item into the collection:
public void Add(NameValueItem item)
{
if (!Contains(item))
List.Add(item);
}
As bog standard, straightforward and easy as this code appears it's proving to be a little sluggish. Is there anything that can be done to improve the performance of this? Or alternatives I could use?
I was considering creating a NameValueHashSet, which is derived from HashSet.
Optional...:
I had a question which I was going to ask in a separate thread, but I'll leave it up to you as to whether you'd like to address it or not.
I wanted to add 2 properties to the NameValueCollection, Names and Values, which return a List of strings from the Collection of NameValueItem objects. Instead I built them into methods GetNames() and GetValues(), as I have to build the collection (i.e. create a List (names/values), iterate over collection adding names/value to List and return List).
Is this a better alternative? In terms of good coding practise, performance, etc.? As my thoughts regarding properties has always been to have it as stripped back as possible, that only references, arithmetic, etc. should exist, with no layers of processes. If that is the case, then it should be built into a method. Thoughts?
Perhaps you shouldn't try to rebuild what the framework already provides? Your implementation of a dictionary is going to perform poorly as it does not scale. The built in Dictionary<TKey, TValue> has O(1) access performance and for most insert and delete operations (unless there are collisions or the internal storage must be expanded).
You can extend the existing dictionary to provide XML serialization support; see this question and answers: Serialize Class containing Dictionary member
As for your second question - Dictionary already provides methods for getting an IEnumerable of the keys and values. This enumerates the keys and/or values as requested by the caller; that is delayed execution and is likely the preferred method over building a full List every time (which requires iterating through all the elements in the dictionary). If the caller wants a list then they just do dictionary.Values.ToList().
We are still using .Net Framework 2.0 / VS 2005 so i do not have LINQ. If i don't want to go with the poor man's LINQ solution, what are some other alternatives for being able to query in memory custom objects in a dictionary?
I'm not sure if one of your poor man's LINQ solution is LINQBridge but I used it for a few weeks and it seemed to be working okay before we actually switched to .NET 3.5 and the real deal.
Dictionary<T> would seem like a good choice, although you haven't provided much information about what you mean by "query." Are you just looking to retrieve data based on some key value? Get a count of total items? Do a sum or average based on some condition? You really need to give more information to get a better answer.
To elaborate on what Chesso said, you'll have to iterate the loop just like LINQ does...
for example:
static T FindFirst<T>(IEnumerable<T> col, Predicate<T> predicate)
{
foreach(T t in col)
{
if(predicate(t))
{
return t;
}
}
return default(T);
}
I was not aware of the Predicate delegate, that seems to be pretty much what i was looking for. As far as the context for which i'm querying:
Say i have a object X with properties A (name, guaranteed to be unique) and B (age)
1) I have a series of objects in a dictionary whose keys are say Property A of a given object, and of course the value is the object iself.
Now i want to retrieve all objects in this dictionary which meet a certain criteria of B, say age > 20.
I can add all the values of the dictionary into a list then call the .FindAll on it, passing in a delegate. I can create an anonymous delegate to do this, but say i will reuse this many times. How can i dynamically specify an age criteria for the delegate method? Would the only choice be to encapsulate the Predicate method in a class, then create a new instance of that class with my criteria as an instance variable?
I currently have an arraylist containing classes in C#. The arraylist is filled like this:
foreach (XmlElement Path in locaties)
{
ISoundSource track = engine.AddSoundSourceFromFile(Path.InnerXml);
mixarray.Add(track);
}
then the array has many ISoundSource classes as its items. Now the thing that sets them apart in the array is their 'name' property. Later on I want to get the ISoundSource from the array by doing a search. I looked up on how to search arraylists and it is said to use a binarysearch but I don't see a way to look up an object with a certain property. How can I get the item from the array which has the name I specify?
You should probably use a Dictionary<,> as it will be much easier to maintain. Also, you should use List<> instead of ArrayList. If you must use BinarySearch, you will have to pass it a custom implementation of IComparer in order to have it use the Name property. Here's an example with a dictionary:
var dictionary = new Dictionary<string, ISoundSource>();
foreach (XmlElement Path in locaties)
{
ISoundSource track = engine.AddSoundSourceFromFile(Path.InnerXml);
mixarray.Add(track);
dictionary[track.Name] = track;
}
ISoundSource item = dictionary["MyTrackName"];
Check out the two parameter overload of BinarySearch which takes an IComparer as the second parameter - you then need to create a small class that inherits from IComparer that will compare the names of two of your Track objects, and pass an instance of this comparer into the BinarySearch.
There are many ways to do what you're asking for, and the right way depends on information that you haven't provided:
Does the Name property uniquely identify items?
Does every item have a Name?
Does the match have to be exact?
Is it important to know what order the items were originally added to the list in, i.e. the order that they appear in the source XML?
Are you trying to find items given their Name, or access them in order by their Name?
How important is it that this be efficient?
It may be that the right solution is to simply use LINQ to find an item:
ISoundSource track = mixarray
.Cast<ISoundSource>
.Where(x => x.Name == name)
.FirstOrDefault();
which will set track to the first item in the list whose name matches the value you're looking for, and to null if there's no match found. (If you use a List<ISoundSource> instead of an ArrayList, you can omit the Cast<ISoundSource> - one of many, many reasons to use List<T> over ArrayList in most cases.)
Most of the time I'll use a Dictionary<TKey, TValue> for this kind of thing, but that's because most the time the answers to those questions are yes, yes, yes, no, don't care about the order, pretty important.
For posterity, here is an alternative way to generate a dictionary using a simple Linq expression.
var dictionary = locaties
.Select(p->engine.AddSoundSourceFromFile(Path.InnerXml))
.ToDictionary(t->t.Name);
The .Select() transforms each node into an ISoundSource. When done, a collection (IEnumerable of ISoundSource) is returned. The .ToDictionary() then converts that list of ISoundSource to a Dictionary of string, ISoundSource.
This requires .NET Framework 3.5 or higher.
In C#, I find myself using a List<T>, IList<T> or IEnumerable<T> 99% of the time. Is there a case when it would be better to use a HashTable (or Dictionary<T,T> in 2.0 and above) over these?
Edit:
As pointed out, what someone would like to do with the collection often dictates what one should be using, so when would you use a Hashtable/Dictonary<T,T> over a List<T>?
Maybe not directly related to the OPs question, but there's a useful blog post about which collection structure to use at: SortedSets
Basically, what you want to do with the collection determines what type of collection you should create.
To summarise in more detail:
Use IList if you want to be able to enumerate and / or modify the collection (normally adding at end of list)
Use IEnumeration if you just want to enumerate the collection (don't need to add / remove - usually used as a return type)
Use IDictionary if you want to access elements by a key (adding / removing elements quickly using a key)
Use SortedSet if you want to access a collection in a predefined order (most common usage being to access the collection in order)
Overall, use Dictionary if you want to access / modify items by key in no particular order (preferred over list as that's generally done in order, preferred over enumeration as you can't modify an enumeration, preferred over hashtable as that's not strictly typed, preferred over sortedlist when you don't need keys sorted)
You use a hashtable (dictionary) when you want fast look up access to an item based on a key.
If you are using List, IList or IEnumerable generally this means that you are looping over data (well in the case of IEnumerable it definitely means that), and a hashtable isn't going to net you anything. Now if you were looking up a value in one list and using that to access data in another list, that would a little different. For example:
Find position in list of Item foo.
Position in list for foo corresponds to position in another list which contains Foo_Value.
Access position in seconds list to get Foo_Value.
Here is a link describing the different datatypes.
Another link.
Use a hashtable, when you need to be able to (quickly) look up items by key.
Of course, you can search through an IList or IEnumerable etc for a matching key but that will take O(n) time rather than O(1) for Hashtable or Dictionary.
Hash-tables are good choices if you are often doing "for something in collection" and you aren't concerned about the order of items in the collection.
Hash-tables are indexes. You can maintain a hash-table to index a list, so you can both choice to access it in order or randomly based upon the key.
Hashtable optimizes lookups. It computes a hash of each key you add. It then uses this hash code to look up the element very quickly. It is an older .NET Framework type. It is slower than the generic Dictionary type.
You're not really comparing the same things, when I use a dictionary it's because I want to have a lookup for the data, usually I want to store a list of objects and I want to be able to quickly look them up using a key of some kind.
I use Hashtables quite often to send back key/value collections to Javascript via page methods.
Dictionaries are good for caching things when you need to retrieve an object given its ID but don't want to have to hit the database: Assuming your collection is not large enough to induce a large number of collisions and your data needs retrieving often enough for an IEnumerable to be too slow, Dictionaries can give a decent speed-up.
There's no way of telling exactly without knowing what the collection is for, but unless the items in your collection are unique you cannot use a hashtable, as there will be nothing to use as a key. So perhaps the rule of thumb you are looking for is that if your members are all different and you want to pull individual instances out by key, use a hashtable. If you have a bunch of items that you wish to treat in the same way (such as doing a foreach on the entire set) use a list.