I have the following structure in my code Dictionary<TKeys, TValues> data;
. I run some LINQ queries on both data types and often need to switch between Keys
and Values
. What is the best way to get the list of Keys for given Values and vice versa? Please, notice, that I usually have 'IEnumerable' and 'IEnumerable' as a result of my previous LINQ queries and would like to have something like IEnumerable<TKeys> Dictionary.GetAllKeys(IEnumerable<IValues> vals)
and IEnumerable<TValues> Dictionary.GetAllValues(IEnumerable<IKeys> keys)
.
我的代码字典
Maybe I need other data container for this task?
也许我需要其他数据容器来完成这项任务?
Regards, Alexander.
此致,亚历山大。
3 个解决方案
#1
29
var values = dictionary.Where(x => someKeys.Contains(x.Key)).Select(x => x.Value);
var keys = dictionary.Where(x => someValues.Contains(x.Value)).Select(x => x.Key);
#2
10
A Dictionary<,>
really isn't great for finding keys by value. You could write a bidirectional dictionary, as I have done in this answer, but it wouldn't necessarily be the best approach.
字典<,>真的不适合按值查找键。你可以写一个双向字典,正如我在这个答案中所做的那样,但它不一定是最好的方法。
Of course you can use a dictionary as a sequence of key/value pairs, so you could have:
当然,您可以使用字典作为键/值对的序列,因此您可以:
var keysForValues = dictionary.Where(pair => values.Contains(pair.Value))
.Select(pair => pair.Key);
Just be aware this will be an O(n) operation, even if your "values" is a HashSet
or something similar (with an efficient containment check).
请注意,这将是一个O(n)操作,即使您的“值”是HashSet或类似的东西(使用有效的包含检查)。
EDIT: If you don't really need a key/value relation - if it's more like they're just pairs - then using List<Tuple<Foo, Bar>>
would make a certain amount of sense. The query ends up being the same, basically:
编辑:如果你真的不需要键/值关系 - 如果它更像是它们只是成对 - 那么使用List
public IEnumerable<T1> GetAllFirst<T1, T2>(IEnumerable<Tuple<T1, T2>> source,
IEnumerable<T2> seconds)
{
HashSet<T2> secondsSet = new HashSet<T2>(seconds);
return source.Where(pair => secondsSet.Contains(pair.Item2));
}
public IEnumerable<T2> GetAllSecond<T1, T2>(IEnumerable<Tuple<T1, T2>> source,
IEnumerable<T1> firsts)
{
HashSet<T1> firstsSet = new HashSet<T1>(firsts);
return source.Where(pair => firstsSet.Contains(pair.Item1));
}
#3
1
The best approach is to perform your linq query on the collection of key-value pairs, then use a Select projection to select either the Keys or the Values at the end of your query. This way there is no need to perform a look-up at the end of your query.
最好的方法是对键值对的集合执行linq查询,然后使用Select投影选择查询末尾的Keys或Values。这样就无需在查询结束时执行查找。
For example:
例如:
Dictionary<string, string> data = new Dictionary<string, string>();
// select all values for keys that contain the letter 'A'
var values = data.Where(pair => pair.Key.Contains("A"))
.Select(pair => pair.Value);
#1
29
var values = dictionary.Where(x => someKeys.Contains(x.Key)).Select(x => x.Value);
var keys = dictionary.Where(x => someValues.Contains(x.Value)).Select(x => x.Key);
#2
10
A Dictionary<,>
really isn't great for finding keys by value. You could write a bidirectional dictionary, as I have done in this answer, but it wouldn't necessarily be the best approach.
字典<,>真的不适合按值查找键。你可以写一个双向字典,正如我在这个答案中所做的那样,但它不一定是最好的方法。
Of course you can use a dictionary as a sequence of key/value pairs, so you could have:
当然,您可以使用字典作为键/值对的序列,因此您可以:
var keysForValues = dictionary.Where(pair => values.Contains(pair.Value))
.Select(pair => pair.Key);
Just be aware this will be an O(n) operation, even if your "values" is a HashSet
or something similar (with an efficient containment check).
请注意,这将是一个O(n)操作,即使您的“值”是HashSet或类似的东西(使用有效的包含检查)。
EDIT: If you don't really need a key/value relation - if it's more like they're just pairs - then using List<Tuple<Foo, Bar>>
would make a certain amount of sense. The query ends up being the same, basically:
编辑:如果你真的不需要键/值关系 - 如果它更像是它们只是成对 - 那么使用List
public IEnumerable<T1> GetAllFirst<T1, T2>(IEnumerable<Tuple<T1, T2>> source,
IEnumerable<T2> seconds)
{
HashSet<T2> secondsSet = new HashSet<T2>(seconds);
return source.Where(pair => secondsSet.Contains(pair.Item2));
}
public IEnumerable<T2> GetAllSecond<T1, T2>(IEnumerable<Tuple<T1, T2>> source,
IEnumerable<T1> firsts)
{
HashSet<T1> firstsSet = new HashSet<T1>(firsts);
return source.Where(pair => firstsSet.Contains(pair.Item1));
}
#3
1
The best approach is to perform your linq query on the collection of key-value pairs, then use a Select projection to select either the Keys or the Values at the end of your query. This way there is no need to perform a look-up at the end of your query.
最好的方法是对键值对的集合执行linq查询,然后使用Select投影选择查询末尾的Keys或Values。这样就无需在查询结束时执行查找。
For example:
例如:
Dictionary<string, string> data = new Dictionary<string, string>();
// select all values for keys that contain the letter 'A'
var values = data.Where(pair => pair.Key.Contains("A"))
.Select(pair => pair.Value);