1

I cannot manage to find values from my OrderedDictionary, I was following several posts on the stack, so I don't see what I am not doing good?

private List<IfcElement> readListParamFromList(Int32 index, OrderedDictionary ifcList)
{
    List<IfcElement> retour = new List<IfcElement>();
    if (this.ListParams[index] != "")
    {
        string[] listStrings = this.ListParams[index].Split(',');

        foreach (string idString in listStrings)
        {
            long idElt = -1;
            idElt = IfcGlobal.GetIdFromIfcString(idString);
            try
            {
                object objectFound = (IfcElement)ifcList[(object)idElt];
                IfcElement newElt = (IfcElement)objectFound;
                retour.Add(newElt);
                this.addChildren(newElt);
            }
            catch
            {
                this.ErrorFound = true;
                this.ListItemsNotFound.Add(idElt);
            }
        }
    }
    return retour;
}

Here I find IdElt=104. Then I checked in debug, my OrderedDictionary has an element inside with Key=104, and object is present in value, but the line object objectFound = (IfcElement)ifcList[(object)idElt]; is always returning null. Is there something wrong with my syntax? Maybe it helps, I add the way I add elements in my dictionary :

public class GroupedListElements
{
    public string Type { get; set; } = "";
    public OrderedDictionary ListIfcElements = new OrderedDictionary();
    public GroupedListElements()
    {

    }
}

GroupedListElements newGroupList = new GroupedListElements { Type = 

newElt.GetType().Name };
newGroupList.ListIfcElements.Add(newElt.ID, newElt);
this.ListGroupped.Add(newGroupList);
Siegfried.V
  • 1,508
  • 1
  • 16
  • 34

1 Answers1

2

I think the problem is that by casting to (object) before retrieving the object from the ordered dictionary, the dictionary tries to locate the key based on Object.Equals(). Object.Equals returns true if the boxed long objects have the same reference (i.e. the ReferenceEquals method returns true). If you don't mind using strings instead of longs as keys, I would recommend to do so.

To see in detail what's going wrong with your code, maybe replace the following line

object objectFound = (IfcElement)ifcList[(object)idElt];

with

object objectKey = (object)idElt;
object objectFound = (IfcElement)ifcList[objectKey];

And then look in the immediate Window of the debugger whether objectKey.ReferenceEquals(x) returns true for any x in

ifcList.Keys
Hermann.Gruber
  • 1,257
  • 1
  • 12
  • 37
  • in fact I tried to replace all by strings, but I had the same issue. Something strange (or I didn't understand something), is if I use `Dictionary` all is working fine, but using OrderedDictionary not. – Siegfried.V Dec 09 '20 at 09:15
  • @Siegfried.V: there is also a generic SortedDictionary – Johan Donne Dec 09 '20 at 09:19
  • @JohanDonne I am pretty new to all generic and dictionaries things. The problem is when I add the elements in my dictionary, I am not sure to add them "in the good order", can insert ID 1200, then 1000 ... So I believed OrderedDictionary would do the job. What I am looking is a dictionary, where I also could concatenate them (I made a separated function). Until now I used the `List`, but I saw that using dictionaries, it may be faster. – Siegfried.V Dec 09 '20 at 09:22
  • 2
    @Siegfried V. A SortedDictionary would do exactly what you want: no matter in what sequence it is populated, it is automatically sorted by de key-values. Of course that is only relevant if you access the dictionary through its enumerator (foreach...). If you retrieve an element from the dictionary through its key, the ordering is irrelevant (that's the whole point of a dictionary). – Johan Donne Dec 09 '20 at 09:24
  • I agree. If you want t maintain the keys in exactly the order in which they were inserted (e.g. 1200,1000, if you inserted first 1200 and then 1000), choose an OrderedDictionary. If you simply want to maintain the keys according to their natural order (i.e. 1000,1200,...) then choose a SortedDictionary. – Hermann.Gruber Dec 09 '20 at 09:31
  • @JohanDonne in fact all worked with SortedDictionary, the strange thing is it doesn't go faster than with List. With List I made an algorythm to search elements : I put the ID always in the good order (so need sometimes(but rarely) to reorder them. Then let's say the time needed to find an element is log(size), for a List of 1024 elements, I find it after 10 reads, if list is 1 million elements, in 20 reads I find it, maybe the Dictionary algorythm works the same way as I did? – Siegfried.V Dec 09 '20 at 09:52
  • 2
    @Siegfried.V Since Dictionary provides direct access for any element through the hashcode of its key, it should outperform a binary search in a List as soon as you have a significant number of elements. There have been a lot of comparisons between the two, e.g. https://www.dotnetperls.com/dictionary-time or https://theburningmonk.com/2011/03/hashset-vs-list-vs-dictionary/ – Johan Donne Dec 09 '20 at 10:35
  • @JohanDonne I know about it (read already about it), but I think this would be true if I used `FirstOrDefault` function, as it has to look each element in my list, and I have my own function that, as I wrote, search faster (20 iterations for 1 million elements). In total I search in 1.5 Million elements, and dictionary is no faster than that. Just that this makes me think about which of them I may keep. Advantage of using dictionary is just that I just can remove my algorythm from my code, so to make it smaller. – Siegfried.V Dec 09 '20 at 10:40
  • @JohanDonne just to explain how works my "algorythm" : I have one thousand elements, each of them have an ID (not necessary 1,2,3,4..., but 1, 11, 23, 50...). I check ID of myList[500], if smaller than expected, I read at position 500+250=750, else I read at 500-250. Then I do the same until I find the good one, so if I have 1000 elements, in 10 times I find it, if 1 Million, 20 times, one Billion 30 times... – Siegfried.V Dec 09 '20 at 10:44
  • @Siegfried.V: Both your Binary search and access to an element in a SortedDictionary have a Time Complexity of O(log n) so they will be equally fast/slow. If you don't need the elements in your dictionary to be kept in a specific order (ordered or sorted on the key) an ordinary Dictionary would be much faster (Time Complexity O(1), essentially returning any element immediately). – Johan Donne Dec 09 '20 at 10:54
  • @JohanDonne In fact, that's why I wanted to use ordinary dictionary (because complexity O(1)), but the point is I have different dictionaries, that I sometimes need to concatenate them. With List, I just use AddRange, then myNewList.OrderBy(x=>x.ID), and that makes the job. But with ordinary dictionary, I think (or didn't find how to do it), I cannot use that kind of operations? If I just concatenate the 2 dictionaries, then order may be not good already? (or I didn't understand how work ordinary dictionaries?), what you call ordinary dictionary is `Dictionary`, right? – Siegfried.V Dec 09 '20 at 11:02
  • 2
    Siegfried.V One thing to consider besides the access-time is that a Dictionary cannot have duplicates (no duplicate keys, that is). A List can. So if you concatenate two Lists, you could end up with two elements having the same key Value. An interesting post about this: https://stackoverflow.com/questions/294138/merging-dictionaries-in-c-sharp – Johan Donne Dec 09 '20 at 11:20
  • @JohanDonne in my case, duplicates never happen. Well I think I will stay with my list, cause on the end the benefit is almost 0, and lot of job to re-code everything. Thanks a lot for your acomments, anyway will have to use Dictionaries for other situations.\ – Siegfried.V Dec 09 '20 at 11:38
  • 1
    Just an edit for whom would come by here. I finally decided to make several tests (on very big datas it makes the difference), and the best way I found was to use Dictionary, as Johan Donne wrote, to get complexity O(1) really increases speed. I didn't expect such a big difference, but it is just enormous... – Siegfried.V May 30 '21 at 06:34