Reputation: 147
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
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
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
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
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
Reputation: 1507
Try this:
var result = yourDictionary.SkipWhile(_keyValue => _keyValue .Key != currentKey).Where(_keyValue => _keyValue.Value == true);
Upvotes: 0