Digika
Digika

Reputation: 147

Selecting next element (KeyValue) in Dictionary by Value state starting from current [Linq]

I was curious if there is more nice looking, simpler (? probably debatable in case with Linq :p) way to select any next Dictionary element that is not current selected.

Let's say I have a Dictionary<string,bool>, I have stored one of the default/first keys, now I need to select next element that has Value "true" (and start over if reached the end) without foreach/loop cycle.

I know that Dictionary isn't ordered but I don't care in this case. As long as nextKey != currentKey and the search goes further from currentKey rather than starting from FirstOrDefault (unless it is "the end" of Dictionary) I'm good for now.

Example:

public Dictionary<string,bool> myDic = new Dictionary<string,bool>(5);
myDic.Add("test1", false);
myDic.Add("test2", true);
myDic.Add("test3", false);
myDic.Add("test4", true);
myDic.Add("test5", true);

Now I select first Key and if it is true, I save it separately. Otherwise OR on request - I need to find next Key that has Value true starting from current selected. So let's say I select use ElementAt(1) and it is test1. Because Value is false I need to get next one that will be true, that's be test2. As I said, I'd like to avoid explicit loops like foreach/for/while/etc.

Upvotes: 0

Views: 2037

Answers (5)

Pikoh
Pikoh

Reputation: 7703

What I would do is just select all the values with value==true,skip to the currentKey element,and then get the next element, something like:

public Dictionary<string,bool> myDic = new Dictionary<string,bool>(5);      
myDic.Add("test1", false);
myDic.Add("test2", true);
myDic.Add("test3", false);
myDic.Add("test4", true);
myDic.Add("test5", true);
string currentKey;
KeyValuePair<string,bool> res;
if (currentKey==null)
{
    res=myDic.Where(x => x.Value).FirstOrDefault();
}
else
{
    res=myDic.Where(x => x.Value).SkipWhile(x => x.Key !=             
          currentKey).Skip(1).FirstOrDefault();
}
if (res.Key!=null)
{
     currentKey=res.Key;
     Console.WriteLine(currentKey);
}
else
{
    Console.WriteLine("Result is null");
} 

Upvotes: 2

shA.t
shA.t

Reputation: 16968

Simple answer is: No, you cannot do it without using any foreach/loop cycle.
Consider that all linq-to-object codes are some kind of foreach/loop cycle.

But if you don't like to see those loop inside of your current page, you can make an extension method like this:

public static TKey GetNextKeyByValue<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, 
    TKey currentKey, TValue nextValue)
{
    var ckFounded = false;
    // if `currentkey` is last key of dictionary it will check for value from start again
    for (var i = 0; i < 2; i++)
    {
        foreach (var pair in dictionary)
        {
            if (ckFounded && pair.Value.Equals(nextValue))
            {
                return pair.Key;
            }
            if (pair.Key.Equals(currentKey) || (currentKey?.Equals(default(TKey)) ?? true))
            {
                ckFounded = true;
            }
        }
    }

    throw new Exception("Key not found");
}

Use it like this:

//var nextKey = yourDictionary.GetNextKeyByValue(currentKey, nextValue);
var firstKey = myDic.GetNextKeyByValue(default(string) /* or null */, true);
var nextKey = myDic.GetNextKeyByValue(firstKey, true);

Upvotes: 0

Kaitiff
Kaitiff

Reputation: 473

With the idea of @Abdullah-dibas, this may work for you.

var m = myDic.SkipWhile(x => x.Value && x.Key != myDic.First().Key)?.First();

I've seen you are with C# 2.0, so a change is needed:

var m = myDic.SkipWhile(x => x.Value && x.Key != myDic.First().Key);
if (m != null && m.Count() > 0)
{
    var element = m.First();
    //And do whatever
}

Upvotes: 0

jdweng
jdweng

Reputation: 34421

Use an enumerator :

            Dictionary<string, bool> dict = new Dictionary<string, bool>();

            List<string> keys = dict.Keys.AsEnumerable().ToList();
            List<string>.Enumerator dictEnumerator = keys.GetEnumerator();

Upvotes: 0

Abdullah Dibas
Abdullah Dibas

Reputation: 1507

Try this:

var result = yourDictionary.SkipWhile(_keyValue => _keyValue .Key != currentKey).Where(_keyValue => _keyValue.Value == true);

Upvotes: 0

Related Questions