从当前[Linq]开始按值状态选择字典中的下一个元素(KeyValue)
Selecting next element (KeyValue) in Dictionary by Value state starting from current [Linq]
我很好奇是否有更好看、更简单(?在使用 Linq 的情况下可能有争议 :p)的方法 select 任何下一个不是当前 selected 的字典元素。
假设我有一个 Dictionary<string,bool>
,我已经存储了一个 default/first 键,现在我需要 select 下一个具有值 "true" 的元素(并且如果到达终点重新开始)没有foreach/loop循环。
我知道字典没有排序,但我不关心这种情况。只要 nextKey != currentKey
并且搜索从 currentKey
开始,而不是从 FirstOrDefault
开始(除非它是词典的 "the end")我现在很好。
示例:
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);
现在我select先Key,如果是真的,我单独保存。 否则或根据要求 - 我需要从当前 selected 开始找到下一个值为 true 的键。所以假设我 select 使用 ElementAt(1)
而它是 test1
。因为 Value
是 false
,所以我需要得到下一个 true
,即 test2
。正如我所说,我想避免像 foreach/for/while/etc.
这样的显式循环
试试这个:
var result = yourDictionary.SkipWhile(_keyValue => _keyValue .Key != currentKey).Where(_keyValue => _keyValue.Value == true);
我要做的只是 select 所有带 value==true
的值,跳到 currentKey 元素,然后获取下一个元素,例如:
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");
}
使用枚举器:
Dictionary<string, bool> dict = new Dictionary<string, bool>();
List<string> keys = dict.Keys.AsEnumerable().ToList();
List<string>.Enumerator dictEnumerator = keys.GetEnumerator();
根据@Abdullah-dibas 的想法,这可能对您有用。
var m = myDic.SkipWhile(x => x.Value && x.Key != myDic.First().Key)?.First();
我看到您使用的是 C# 2.0,因此需要进行更改:
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
}
简单的回答是:不行,你不能不使用任何foreach
/loop cycle.
考虑到所有 linq-to-object 代码都是某种 foreach
/loop 循环。
但是,如果您不希望在当前页面中看到这些循环,您可以创建这样的扩展方法:
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");
}
这样使用:
//var nextKey = yourDictionary.GetNextKeyByValue(currentKey, nextValue);
var firstKey = myDic.GetNextKeyByValue(default(string) /* or null */, true);
var nextKey = myDic.GetNextKeyByValue(firstKey, true);
我很好奇是否有更好看、更简单(?在使用 Linq 的情况下可能有争议 :p)的方法 select 任何下一个不是当前 selected 的字典元素。
假设我有一个 Dictionary<string,bool>
,我已经存储了一个 default/first 键,现在我需要 select 下一个具有值 "true" 的元素(并且如果到达终点重新开始)没有foreach/loop循环。
我知道字典没有排序,但我不关心这种情况。只要 nextKey != currentKey
并且搜索从 currentKey
开始,而不是从 FirstOrDefault
开始(除非它是词典的 "the end")我现在很好。
示例:
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);
现在我select先Key,如果是真的,我单独保存。 否则或根据要求 - 我需要从当前 selected 开始找到下一个值为 true 的键。所以假设我 select 使用 ElementAt(1)
而它是 test1
。因为 Value
是 false
,所以我需要得到下一个 true
,即 test2
。正如我所说,我想避免像 foreach/for/while/etc.
试试这个:
var result = yourDictionary.SkipWhile(_keyValue => _keyValue .Key != currentKey).Where(_keyValue => _keyValue.Value == true);
我要做的只是 select 所有带 value==true
的值,跳到 currentKey 元素,然后获取下一个元素,例如:
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");
}
使用枚举器:
Dictionary<string, bool> dict = new Dictionary<string, bool>();
List<string> keys = dict.Keys.AsEnumerable().ToList();
List<string>.Enumerator dictEnumerator = keys.GetEnumerator();
根据@Abdullah-dibas 的想法,这可能对您有用。
var m = myDic.SkipWhile(x => x.Value && x.Key != myDic.First().Key)?.First();
我看到您使用的是 C# 2.0,因此需要进行更改:
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
}
简单的回答是:不行,你不能不使用任何foreach
/loop cycle.
考虑到所有 linq-to-object 代码都是某种 foreach
/loop 循环。
但是,如果您不希望在当前页面中看到这些循环,您可以创建这样的扩展方法:
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");
}
这样使用:
//var nextKey = yourDictionary.GetNextKeyByValue(currentKey, nextValue);
var firstKey = myDic.GetNextKeyByValue(default(string) /* or null */, true);
var nextKey = myDic.GetNextKeyByValue(firstKey, true);