C# 从数组中访问字典值
C# Access Dictionary value from array
比如说,我有一个未确定长度的 string[]
和一个 Dictionary<string, object>
,其中包含更多与其确切类型(或其他类型,这在这里无关紧要)的词典。
现在我想根据我的字符串数组更改字典中 Dictionary
中 Dictionary
中的值。
这是一个小可视化:
string[]: { "Human", "Legs", "Walking" }
Dictionary:
↳ Key "Human":
↳ Key "Legs":
↳ Key "Walking"
我想在这个例子中设置键“Walking”的值(让我们说 true
)
现在我的问题是:如何在 C# 中实现这个?
任何答案将不胜感激,如果我想多了,请原谅。
因为你对 TValue
使用 Object
,所以你需要使用 x is T v
运算符来测试 Object
是否是另一个字典,例如if( x is Dictionary<String,Object> dict )
.
这里的困难是你不能将 x is T v
与 strongly-typed T
一起使用,因为 IReadOnlyDictionary<K,V>
与 V
不协变,即使你知道 K
是什么(因为 C# 和 .NET 不支持 partially-closed 泛型)。
...但是如果你不 need/want exactly-typed 类型并且假设你的图表中的 all 字典对象总是 exactly Dictionary<String,Object>
(而不是Dictionary<String,Int32>
或Dictionary<String,String>
)那么你可以这样做:
String[] dictPath = new[] { "Human", "Legs", "Walking" };
Dictionary<String,Object> dictGraph = ...
Object humanLegsWalkingValue = GetValueAtPath( dictGraph, dictPath );
//
static Object? GetValueAtPath( Dictionary<String,Object> root, String[] dictPath )
{
List<String> breadcrumbs = new List<String>(); // For reporting errors.
Dictionary<String,Object> current = root;
foreach( String name in dictPath )
{
breadcrumbs.Add( name );
if( current.TryGetValue( name, out Object? value ) )
{
if( value is Dictionary<String,Object> dict )
{
current = dict;
}
else
{
if( breadcrumbs.Count == dictPath.Length )
{
return value;
}
else
{
String valueType = value is null ? "null" : value.GetType().FullName;
const String MSG_FMT = "Value at \"{0}\" is not a dictionary but is actually {1}, therefore \"{2}\" is unreachable."
throw new InvalidOperationException( String.Format( MSG_FMT, String.Join( ".", breadcrumbs ), valueType, String.Join( ".", dictPath ) ) );
}
}
}
else
{
const String MSG_FMT = "Could not find name \"{0}\" at \"{1}\" therefore \"{2}\" is unreachable."
throw new KeyNotFoundException( String.Format( MSG_FMT, name, String.Join( ".", breadcrumbs ), String.Join( ".", dictPath ) ) );
}
}
}
要设置一个值,它使用几乎完全相同的逻辑来遍历dictionary-graph,除了它停止1 -dictPath
末尾的一步,并使用它在 current
中设置一个条目:
static void SetValueAtPath( Dictionary<String,Object> root, String[] dictPath, Object newValue )
{
List<String> breadcrumbs = new List<String>(); // For reporting errors.
Dictionary<String,Object> current = root;
foreach( ( String name, Int32 idx ) in dictPath.Select( ( n, i ) => ( n, i ) ) )
{
breadcrumbs.Add( name );
if( idx == dictPath.Length - 1 )
{
current[ name ] = newValue;
return;
}
else if( current.TryGetValue( name, out Object? value ) )
{
if( value is Dictionary<String,Object> dict )
{
current = dict;
}
else
{
String valueType = value is null ? "null" : value.GetType().FullName;
const String MSG_FMT = "Value at \"{0}\" is not a dictionary but is actually {1}, therefore {2} is unreachable."
throw new InvalidOperationException( String.Format( MSG_FMT, String.Join( ".", breadcrumbs ), valueType, String.Join( ".", dictPath ) );
}
}
else
{
const String MSG_FMT = "Could not find name \"{0}\" at \"{1}\" therefore \"{2}\" is unreachable."
throw new KeyNotFoundException( String.Format( MSG_FMT, name, String.Join( ".", breadcrumbs ), String.Join( ".", dictPath ) ) );
}
}
}
这可能不是对您问题的(直接)回答:
string[] strs = new string[] { "Human", "Legs", "Walking" };
Dictionary<string,string> dict = new Dictionary<string, string>();
for(int i=0; i<strs.Length; i++) {
dict.Add(strs[i],(i>0?strs[i-1]:""));
}
string find = "Human";
if(dict.ContainsKey(find)) {
System.Console.WriteLine($"Hello: {find}");
foreach (var item in dict.Where(x=>x.Value==find))
{
System.Console.WriteLine($"You have: {item.Key}");
foreach (var item2 in dict.Where(x=>x.Value==item.Key))
{
System.Console.WriteLine($"Which can make you: {item2.Key}");
}
}
}
else
{
System.Console.WriteLine($"Could not find: {find}");
}
输出:
Hello: Human
You have: Legs
Which can make you: Walking
注意:目前还不清楚为什么你的问题标题有 Dictionary
并且你开始定义一个数组 (string[]
)。
比如说,我有一个未确定长度的 string[]
和一个 Dictionary<string, object>
,其中包含更多与其确切类型(或其他类型,这在这里无关紧要)的词典。
现在我想根据我的字符串数组更改字典中 Dictionary
中 Dictionary
中的值。
这是一个小可视化:
string[]: { "Human", "Legs", "Walking" }
Dictionary:
↳ Key "Human":
↳ Key "Legs":
↳ Key "Walking"
我想在这个例子中设置键“Walking”的值(让我们说 true
)
现在我的问题是:如何在 C# 中实现这个?
任何答案将不胜感激,如果我想多了,请原谅。
因为你对 TValue
使用 Object
,所以你需要使用 x is T v
运算符来测试 Object
是否是另一个字典,例如if( x is Dictionary<String,Object> dict )
.
这里的困难是你不能将 x is T v
与 strongly-typed T
一起使用,因为 IReadOnlyDictionary<K,V>
与 V
不协变,即使你知道 K
是什么(因为 C# 和 .NET 不支持 partially-closed 泛型)。
...但是如果你不 need/want exactly-typed 类型并且假设你的图表中的 all 字典对象总是 exactly Dictionary<String,Object>
(而不是Dictionary<String,Int32>
或Dictionary<String,String>
)那么你可以这样做:
String[] dictPath = new[] { "Human", "Legs", "Walking" };
Dictionary<String,Object> dictGraph = ...
Object humanLegsWalkingValue = GetValueAtPath( dictGraph, dictPath );
//
static Object? GetValueAtPath( Dictionary<String,Object> root, String[] dictPath )
{
List<String> breadcrumbs = new List<String>(); // For reporting errors.
Dictionary<String,Object> current = root;
foreach( String name in dictPath )
{
breadcrumbs.Add( name );
if( current.TryGetValue( name, out Object? value ) )
{
if( value is Dictionary<String,Object> dict )
{
current = dict;
}
else
{
if( breadcrumbs.Count == dictPath.Length )
{
return value;
}
else
{
String valueType = value is null ? "null" : value.GetType().FullName;
const String MSG_FMT = "Value at \"{0}\" is not a dictionary but is actually {1}, therefore \"{2}\" is unreachable."
throw new InvalidOperationException( String.Format( MSG_FMT, String.Join( ".", breadcrumbs ), valueType, String.Join( ".", dictPath ) ) );
}
}
}
else
{
const String MSG_FMT = "Could not find name \"{0}\" at \"{1}\" therefore \"{2}\" is unreachable."
throw new KeyNotFoundException( String.Format( MSG_FMT, name, String.Join( ".", breadcrumbs ), String.Join( ".", dictPath ) ) );
}
}
}
要设置一个值,它使用几乎完全相同的逻辑来遍历dictionary-graph,除了它停止1 -dictPath
末尾的一步,并使用它在 current
中设置一个条目:
static void SetValueAtPath( Dictionary<String,Object> root, String[] dictPath, Object newValue )
{
List<String> breadcrumbs = new List<String>(); // For reporting errors.
Dictionary<String,Object> current = root;
foreach( ( String name, Int32 idx ) in dictPath.Select( ( n, i ) => ( n, i ) ) )
{
breadcrumbs.Add( name );
if( idx == dictPath.Length - 1 )
{
current[ name ] = newValue;
return;
}
else if( current.TryGetValue( name, out Object? value ) )
{
if( value is Dictionary<String,Object> dict )
{
current = dict;
}
else
{
String valueType = value is null ? "null" : value.GetType().FullName;
const String MSG_FMT = "Value at \"{0}\" is not a dictionary but is actually {1}, therefore {2} is unreachable."
throw new InvalidOperationException( String.Format( MSG_FMT, String.Join( ".", breadcrumbs ), valueType, String.Join( ".", dictPath ) );
}
}
else
{
const String MSG_FMT = "Could not find name \"{0}\" at \"{1}\" therefore \"{2}\" is unreachable."
throw new KeyNotFoundException( String.Format( MSG_FMT, name, String.Join( ".", breadcrumbs ), String.Join( ".", dictPath ) ) );
}
}
}
这可能不是对您问题的(直接)回答:
string[] strs = new string[] { "Human", "Legs", "Walking" };
Dictionary<string,string> dict = new Dictionary<string, string>();
for(int i=0; i<strs.Length; i++) {
dict.Add(strs[i],(i>0?strs[i-1]:""));
}
string find = "Human";
if(dict.ContainsKey(find)) {
System.Console.WriteLine($"Hello: {find}");
foreach (var item in dict.Where(x=>x.Value==find))
{
System.Console.WriteLine($"You have: {item.Key}");
foreach (var item2 in dict.Where(x=>x.Value==item.Key))
{
System.Console.WriteLine($"Which can make you: {item2.Key}");
}
}
}
else
{
System.Console.WriteLine($"Could not find: {find}");
}
输出:
Hello: Human
You have: Legs
Which can make you: Walking
注意:目前还不清楚为什么你的问题标题有 Dictionary
并且你开始定义一个数组 (string[]
)。