31

My dictionary:

Dictionary<double, string> dic = new Dictionary<double, string>();

How can I return the last element in my dictionary?

nawfal
  • 70,104
  • 56
  • 326
  • 368
subprime
  • 1,217
  • 8
  • 20
  • 34

12 Answers12

68

What do you mean by Last? Do you mean Last value added?

The Dictionary<TKey,TValue> class is an unordered collection. Adding and removing items can change what is considered to be the first and last element. Hence there is no way to get the Last element added.

There is an ordered dictionary class available in the form of SortedDictionary<TKey,TValue>. But this will be ordered based on comparison of the keys and not the order in which values were added.

EDIT

Several people have mentioned using the following LINQ style approach

var last = dictionary.Values.Last();

Be very wary about using this method. It will return the last value in the Values collection. This may or may not be the last value you added to the Dictionary. It's probably as likely to not be as it is to be.

JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • 5
    Upvote for the warning on not using the LINQ style approach as it doesn't return what subprime requires. – RichardOD Jun 19 '09 at 14:36
  • 6
    Although there is no generic version, there is a OrderedDictionary in the System.Collection.Specialized namespace that maintains items in insertion order. – LBushkin Jun 19 '09 at 14:38
  • 1
    @subprime, in that case use LastOrDefault instead of Last. – JaredPar Jun 19 '09 at 15:09
25

Dictionaries are unordered collections - as such, there is no concept of a first or last element. If you are looking for a class that behaves like a dictionary but maintains the insertion order of items, consider using OrderedDictionary.

If you are looking for a collection that sorts the items, consider using SortedDictionary<TKey,TValue>.

If you have an existing dictionary, and you are looking for the 'last' element given some sort order, you could use linq to sort the collection, something like:

myDictionary.Values.OrderBy( x => x.Key ).Last();

By wary of using Dictionary.Keys.Last() - while the key list is sorted using the default IComparer for the type of the key, the value you get may not be the value you expect.

LBushkin
  • 129,300
  • 32
  • 216
  • 265
11

I know this question is too old to get any upvotes, but I didn't like any of the answers so will post my own in the hopes of offering another option to future readers.

Assuming you want the highest key value in a dictionary, not the last inserted:

The following did not work for me on .NET 4.0:

myDictionary.Values.OrderBy( x => x.Key ).Last();

I suspect the problem is that the 'x' represents a value in the dictionary, and a value has no key (the dictionary stores the key, the dictionary values do not). I may also be making a mistake in my usage of the technique.

Either way, this solution would be slow for large dictionaries, probably O(n log n) for CS folks, because it is sorting the entire dictionary just to get one entry. That's like rearranging your entire DVD collection just to find one specific movie.


var lastDicVal = dic.Values.Last();

is well established as a bad idea. In practice, this solution may return the last value added to the dictionary (not the highest key value), but in software engineering terms that is meaningless and should not be relied upon. Even if it works every time for the rest of eternity, it represents a time bomb in your code that depends on library implementation detail.


My solution is as follows:

var lastValue = dic[dic.Keys.Max()];

The Keys.max() function is much faster than sorting O(n) instead of O(n log n). If performance is important enough that even O(n) is too slow, the last inserted key can be tracked in a separate variable used to replace dic.Keys.Max(), which will make the entire lookup as fast as it can be, or O(1).

Note: Use of double or float as a key is not best practice and can yield surprising results which are beyond the scope of this post. Read about "epsilon" in the context of float/double values.

Charles Burns
  • 10,310
  • 7
  • 64
  • 81
5

If you're using .NET 3.5, look at:

 dic.Keys.Last()

If you want a predictable order, though, use:

IDictionary<int, string> dic = new SortedDictionary<int, string>();
Chris Doggett
  • 19,959
  • 4
  • 61
  • 86
  • Every call to "Last()" will return the same result, until an insert or an "Add()" is made, correct? At which point it could possibly be different? – DevinB Jun 19 '09 at 14:20
  • I believe so, but since it's an unordered collection, the last added may be somewhere in the middle of the collection. I'm not sure how it's implemented internally, or what Last() actually returns. Someone with more knowledge of the internals would have to answer that. Unleash the Skeet signal. – Chris Doggett Jun 19 '09 at 14:26
3

Consider creating a custom collection that contains a reference in the Add method of the custom collection. This would set a private field containing the last added key/value(or both) depending on your requirements.

Then have a Last() method that returns this. Here's a proof of concept class to show what I mean (please don't knock the lack of interface implementation etc- it is sample code):

public class LastDictionary<TKey, TValue>
{
    private Dictionary<TKey, TValue> dict;

    public LastDictionary()
    {
        dict = new Dictionary<TKey, TValue>();
    }

    public void Add(TKey key, TValue value)
    {
        LastKey = key;
        LastValue = value;
        dict.Add(key, value);
    }

    public TKey LastKey
    {
        get; private set;
    }

    public TValue LastValue
    {
        get; private set;
    }
}
nawfal
  • 70,104
  • 56
  • 326
  • 368
RichardOD
  • 28,883
  • 9
  • 61
  • 81
  • Clever :-) You could make this more succinct by using automatic properties with private setters and public getters. – Metro Smurf Jun 21 '09 at 17:30
  • @Metro Smurf- very true, thanks. I've updated the code to include these- I believe it makes the example a little easier to read. – RichardOD Jun 21 '09 at 18:16
  • A better way to do this would be to inherit from Dictionary and then just override the Add method, where you would set your added properties, and then call base.Add(key, value). Would save you a lot of trouble delegating all the functions of Dictionary manually. – sprite Mar 11 '12 at 08:04
  • 2
    @Sprite- yes, inheriting dictionary would be a better approach, except Add is not virtual, so you've got an issue there – RichardOD Mar 11 '12 at 20:09
3

Instead of using:

Dictionary<double, string>

...you could use:

List<KeyValuePair<double, string>>

This would allow you to use the indexer to access the element by order instead of by key.

Erick
  • 31
  • 1
1

From the docs:

For purposes of enumeration, each item in the dictionary is treated as a KeyValuePair structure representing a value and its key. The order in which the items are returned is undefined.

So, I don't think you can rely on Dictionary to return the last element.

Use another collection. Maybe SortedDictionary ...

bruno conde
  • 47,767
  • 15
  • 98
  • 117
0

If you just want the value, this should work (assuming you can use LINQ):

dic.Values.Last()
Lance Harper
  • 2,216
  • 14
  • 11
0

You could use:

dic.Last()

But a dictionary doesn't really have a last element (the pairs inside aren't ordered in any particular way). The last item will always be the same, but it's not obvious which element it might be.

Jake Pearson
  • 27,069
  • 12
  • 75
  • 95
0

With .Net 3.5:

string lastItem = dic.Values.Last()
string lastKey = dic.Keys.Last()

...but keep in mind that a dictionary is not ordered, so you can't count on the fact that the values will remain in the same order.

Meta-Knight
  • 17,626
  • 1
  • 48
  • 58
0

A dictionary isn't meant to be accessed in order, so first, last have no meaning. Do you want the value indexed by the highest key?

Dictionary<double, string> dic = new Dictionary<double, string>();
double highest = double.MinValue;
string result = null;
foreach(double d in dic.keys)
{
   if(d > highest)
   {
      result = dic[d];
      highest = d;
   }
}
Hardwareguy
  • 2,941
  • 1
  • 17
  • 13
-1

Instead of using Linq like most of the other answers suggest, you can just access the last element of any Collection object via the Count property (see ICollection.Count Property for more information).

See the code here for an example of how to use count to access the final element in any Collection (including a Dictionary):

Dictionary<double, string> dic = new Dictionary<double, string>();
var lastElementIndex = dic.Count - 1;
var lastElement = dic[lastElementIndex];

Keep in mind that this returns the last VALUE, not the key.

Blairg23
  • 11,334
  • 6
  • 72
  • 72
  • This code is just flat out wrong. A dictionary is unordered and does NOT have an indexer that accepts an index. This code only compiles because the dictionary has a double as a key, therefore ONLY has an indexer that accepts a double. And since an int can be implicitly converted to a double, your third line there only works because the int is being converted to a double. This will return the value corresponding to the key that equals (double)(dic.Count - 1), NOT the last item (and a value with that key might not exist, in which case you get an Exception instead of just a wrong value). – Cedric Mamo Apr 02 '19 at 13:08
  • Your comment only applies specifically to IList or IReadOnlyList which do define an indexer that takes an int index in the interface. ICollection does not. They also contain the Count property taken from the ICollection interface. But that by itself is not enough, because Dictionary implements neither IList nor IReadOnlyList – Cedric Mamo Apr 02 '19 at 13:21