4

Given the code ..

var dictionary = new Dictionary<string, string>{
  { "something", "something-else" },
  { "another", "another-something-else" }
};

dictionary.ForEach( item => {
  bool isLast = // ... ? 

  // do something if this is the last item
});

I basically want to see if the item I am working with inside of the ForEach iteration is the last item in the dictionary. I tried

bool isLast = dictionary[ item.Key ].Equals( dictionary.Last() ) ? true : false;

but that did not work...

Ciel
  • 16,274
  • 19
  • 101
  • 196
  • 1
    Have you tried using a counter and comparing the iterations through the foreach to the size of the dictionary? Dictionaries are theoretically unordered, so I wouldn't trust any comparison to Last value of the dictionary. – ben f. Jun 02 '11 at 14:55
  • 1
    What exactly is "last" in a dictionary? – user7116 Jun 02 '11 at 16:39
  • This question doesn't make much sense because the `Dictionary` collection is not ordered. Take a look at this: [Why is a Dictionary “not ordered”?](https://stackoverflow.com/questions/6384710/why-is-a-dictionary-not-ordered) – Theodor Zoulias Dec 02 '20 at 05:26

8 Answers8

13

Dictionary.Last returns a KeyValuePair, and you are comparing that to just the value of a key. You'd instead need to check:

dictionary[item.Key].Equals( dictionary.Last().Value )

Also IAbstract was correct that you'd probably need to use an OrderedDictionary.

Chris Walsh
  • 1,735
  • 15
  • 16
2

You will want to use an OrderedDictionary<TKey, TValue>. Check MSDN ref.

With the standard Dictionary, items are not guaranteed to be persisted in any specific order.

IAbstract
  • 18,848
  • 14
  • 81
  • 137
1

Some people have mentioned to compare the value of the current item in the iteration to the last item's value, example:

    dictionary[item.Key].Equals(dictionary.Last().Value) 

Warning: This could result in true for any item in the dictionary if the value of the item is equal to the value of the last item in the dictionary. This is not an indicator that the item is the last item in dictionary.


Instead, if you are really trying to find if the current item in the iteration is the last item, I would suggest comparing the Key because you know it is unique, So it might look something like:

    item.Key.Equals(dictionary.Last().Key)
chandler
  • 965
  • 1
  • 12
  • 29
1

You could test if value == dictionary.Values.Last();

Kelly Gendron
  • 6,819
  • 6
  • 40
  • 64
1

Would it not be simpler to just perform the operation on the last item outside of the loop?

string requiredForSomething = dictionary.Last().Value;
Jon Eastwood
  • 803
  • 10
  • 22
1

using the System.Linq namespace, we can do MyDictionary[item.Key].Equals( MyDictionary.Last().Key ); the Last() method should show us, every array, dictionary, list, stack, queue the last element of it.

Cueia Dev
  • 11
  • 3
1

You can always do this with a counter.

int itemsCount = yourDictionary.Count;
bool isLast = false;

foreach(var item in yourDictionary)
{
   itemsCount--;       
   isLast = itemsCount == 0; 

   if(isLast)
   {
     // this is the last item no matter the order of the dictionary        
   }
   else
  {
    //not the last item
  }

}
Atometa
  • 111
  • 2
0

First, there is no ForEach extension method for a Dictionary or even an IEnumerable. So you will have to fix that problem first.

Second, the Last extension method will be painfully slow since it has to enumerate the entire collection.

Third, I am not sure it makes a whole lot of sense to do something special on the last item from a collection with an unpredictable order, but that is mostly tangential to your specific question.

Here is how I would approach the problem. Create two new extensions methods that operate on IEnumerable<T> instances. ForEach will be the equivalent of the List<T>.ForEach method and WithIndex will return another enumerator that contains the sequential index and an IsLast flag. This is a variation of another one of my answers to a similiar problem.

dictionary.WithIndex().ForEach(
  (item) =>
  {
    var kvp = item.Value; // This extracts the KeyValuePair
    if (item.IsLast)
    {
      Console.WriteLine("Key=" + kvp.Key.ToString() + "; Value=" + kvp.Value.ToString());
    }
  });

Here are the new extension methods.

public static class ForEachHelperExtensions
{
    public sealed class Item<T>
    {
        public int Index { get; set; }
        public T Value { get; set; }
        public bool IsLast { get; set; }
    }

    public static void ForEach<T>(this IEnumerable<T> enumerable, Action<T> action)
    {
        foreach (T item in enumerable)
        {
            action(item);
        }
    }

    public static IEnumerable<Item<T>> WithIndex<T>(this IEnumerable<T> enumerable)
    {
        Item<T> item = null;
        foreach (T value in enumerable)
        {
            Item<T> next = new Item<T>();
            next.Index = 0;
            next.Value = value;
            next.IsLast = false;
            if (item != null)
            {
                next.Index = item.Index + 1;
                yield return item;
            }
            item = next;
        }
        if (item != null)
        {
            item.IsLast = true;
            yield return item;
        }
    }
}
Community
  • 1
  • 1
Brian Gideon
  • 45,093
  • 12
  • 98
  • 145