使用 LINQ 的 ToDictionary 方法
本文已参与「新人创作礼」活动,一起开启掘金创作之路。
ToDictionary()
可以用序列(例如数组和list)快速创建Dictionary。
平时我们可能习惯用Foreach把List或数组中的内容转换为Dictionary,代码如下。
using System.Linq;
using System.Collections;
using System.Collections.Generic;
public static class Program
{
private class Parameter
{
public int ID { get; set; }
public int Age { get; set; }
public string Name { get; set; }
public override string ToString()
{
return string.Format( "ID:{0}, Age:{1}, Name:{2}", ID, Age, Name );
}
}
static void Main( string[] args )
{
Parameter[] parameters = new Parameter[]
{
new Parameter() { ID = 0, Age = 52, Name = "正一郎" },
new Parameter() { ID = 8, Age = 28, Name = "清次郎" },
new Parameter() { ID = 3, Age = 20, Name = "誠三郎" },
new Parameter() { ID = 4, Age = 18, Name = "征史郎" },
};
Dictionary<int, Parameter> dictionary = new Dictionary<int, Parameter>();
foreach( var parameter in parameters )
{
dictionary.Add( parameter.ID, parameter );
}
System.Console.WriteLine( "parameters:{0}", parameters.Text() );
System.Console.WriteLine( "dictionary:{0}", dictionary.Text() );
System.Console.ReadKey();
}
public static string Text( this IEnumerable i_source )
{
string text = string.Empty;
foreach( var value in i_source )
{
text += string.Format( "[{0}], ", value );
}
return text;
}
}
parameters:[ID:0, Age:52, Name:正一郎], [ID:8, Age:28, Name:清次郎], [ID:3, Age:
20, Name:誠三郎], [ID:4, Age:18, Name:征史郎],
dictionary:0, ID:0, Age:52, Name:正一郎, 8, ID:8, Age:28, Name:清次郎, [
[3, ID:3, Age:20, Name:誠三郎]], 4, ID:4, Age:18, Name:征史郎,
完成了。这是可行的,但LINQ的ToDictionary()可用于简化代码。
MSDN
要使用ToDictionary(),只需从数组或List中调用它,并描述获取key属性作为参数的过程。value默认为当前的数组或List。
以下示例描述了使用lambda表达式获取key属性的过程。
using System.Linq;
using System.Collections;
using System.Collections.Generic;
public static class Program
{
private class Parameter
{
public int ID { get; set; }
public int Age { get; set; }
public string Name { get; set; }
public override string ToString()
{
return string.Format( "ID:{0}, Age:{1}, Name:{2}", ID, Age, Name );
}
}
static void Main( string[] args )
{
Parameter[] parameters = new Parameter[]
{
new Parameter() { ID = 0, Age = 52, Name = "正一郎" },
new Parameter() { ID = 8, Age = 28, Name = "清次郎" },
new Parameter() { ID = 3, Age = 20, Name = "誠三郎" },
new Parameter() { ID = 4, Age = 18, Name = "征史郎" },
};
Dictionary<int, Parameter> dictionary = parameters.ToDictionary( value => value.ID );
System.Console.WriteLine( "parameters:{0}", parameters.Text() );
System.Console.WriteLine( "dictionary:{0}", dictionary.Text() );
System.Console.ReadKey();
}
public static string Text( this IEnumerable i_source )
{
string text = string.Empty;
foreach( var value in i_source )
{
text += string.Format( "[{0}], ", value );
}
return text;
}
}
parameters:[ID:0, Age:52, Name:正一郎], [ID:8, Age:28, Name:清次郎], [ID:3, Age:
20, Name:誠三郎], [ID:4, Age:18, Name:征史郎],
dictionary:0, ID:0, Age:52, Name:正一郎, 8, ID:8, Age:28, Name:清次郎, [
[3, ID:3, Age:20, Name:誠三郎]], 4, ID:4, Age:18, Name:征史郎,
前面我们value直接使用的是List或数组里的内容,我们也可以通过传入第二个参数自定义value的值。
下面是通过lambda表达式传入value值的例子。
using System.Linq;
using System.Collections;
using System.Collections.Generic;
public static class Program
{
private class Parameter
{
public int ID { get; set; }
public int Age { get; set; }
public string Name { get; set; }
public override string ToString()
{
return string.Format( "ID:{0}, Age:{1}, Name:{2}", ID, Age, Name );
}
}
static void Main( string[] args )
{
Parameter[] parameters = new Parameter[]
{
new Parameter() { ID = 0, Age = 52, Name = "正一郎" },
new Parameter() { ID = 8, Age = 28, Name = "清次郎" },
new Parameter() { ID = 3, Age = 20, Name = "誠三郎" },
new Parameter() { ID = 4, Age = 18, Name = "征史郎" },
};
Dictionary<int, string> dictionary = parameters.ToDictionary( value => value.ID, value => value.Name );
System.Console.WriteLine( "parameters:{0}", parameters.Text() );
System.Console.WriteLine( "dictionary:{0}", dictionary.Text() );
System.Console.ReadKey();
}
public static string Text( this IEnumerable i_source )
{
string text = string.Empty;
foreach( var value in i_source )
{
text += string.Format( "[{0}], ", value );
}
return text;
}
}
parameters:[ID:0, Age:52, Name:正一郎], [ID:8, Age:28, Name:清次郎], [ID:3, Age:
20, Name:誠三郎], [ID:4, Age:18, Name:征史郎],
dictionary:0, 正一郎, 8, 清次郎, 3, 誠三郎, 4, 征史郎,
所以说当仅有一个参数时传入的是key,value默认为当前转换的List或数组的值。(key)
两个参数时第一个为key,第二个为value。(key,value)
当我们传入的键有重复的会怎么样呢?
using System.Linq;
using System.Collections;
using System.Collections.Generic;
public static class Program
{
private class Parameter
{
public int ID { get; set; }
public int Age { get; set; }
public string Name { get; set; }
public override string ToString()
{
return string.Format( "ID:{0}, Age:{1}, Name:{2}", ID, Age, Name );
}
}
static void Main( string[] args )
{
Parameter[] parameters = new Parameter[]
{
new Parameter() { ID = 0, Age = 52, Name = "正一郎" },
new Parameter() { ID = 8, Age = 28, Name = "清次郎" },
new Parameter() { ID = 4, Age = 20, Name = "誠三郎" },
new Parameter() { ID = 4, Age = 18, Name = "征史郎" },
};
Dictionary<int, Parameter> dictionary = null;
try
{
dictionary = parameters.ToDictionary( value => value.ID );
}
catch( System.Exception i_exception )
{
System.Console.WriteLine( "{0}", i_exception );
System.Console.ReadKey();
return;
}
System.Console.WriteLine( "parameters:{0}", parameters.Text() );
System.Console.WriteLine( "dictionary:{0}", dictionary.Text() );
System.Console.ReadKey();
}
public static string Text( this IEnumerable i_source )
{
string text = string.Empty;
foreach( var value in i_source )
{
text += string.Format( "[{0}], ", value );
}
return text;
}
}
System.ArgumentException: 包含相同键的项已添加。
注意如果传入相同key值会报错。
前面用的都是值类型作为key,下面尝试下用引用类型作为key。
using System.Linq;
using System.Collections;
using System.Collections.Generic;
public static class Program
{
private class KeyData
{
public int ID { get; set; }
public string Version { get; set; }
public override string ToString()
{
return string.Format( "{0}_{1}", ID, Version );
}
}
private class Parameter
{
public KeyData Key { get; set; }
public string Name { get; set; }
public override string ToString()
{
return string.Format( "Key:{0}, Name:{1}", Key, Name );
}
}
static void Main( string[] args )
{
Parameter[] parameters = new Parameter[]
{
new Parameter() { Key = new KeyData() { ID = 0, Version = "A" }, Name = "正一郎" },
new Parameter() { Key = new KeyData() { ID = 0, Version = "B" }, Name = "清次郎" },
new Parameter() { Key = new KeyData() { ID = 2, Version = "C" }, Name = "誠三郎" },
new Parameter() { Key = new KeyData() { ID = 2, Version = "C" }, Name = "征史郎" },
};
Dictionary<KeyData, Parameter> dictionary = null;
try
{
dictionary = parameters.ToDictionary( value => value.Key );
}
catch( System.Exception i_exception )
{
System.Console.WriteLine( "{0}", i_exception );
System.Console.ReadKey();
return;
}
System.Console.WriteLine( "parameters:{0}", parameters.Text() );
System.Console.WriteLine( "dictionary:{0}", dictionary.Text() );
try
{
Parameter result = dictionary[ new KeyData() { ID = 2, Version = "C" } ];
System.Console.WriteLine( "result:{0}", result );
}
catch( System.Exception i_exception )
{
System.Console.WriteLine( "{0}", i_exception );
System.Console.ReadKey();
return;
}
System.Console.ReadKey();
}
public static string Text( this IEnumerable i_source )
{
string text = string.Empty;
foreach( var value in i_source )
{
text += string.Format( "[{0}], ", value );
}
return text;
}
}
parameters:[Key:0_A, Name:正一郎], [Key:0_B, Name:清次郎], [Key:2_C, Name:誠三郎
], [Key:2_C, Name:征史郎],
dictionary:0_A, Key:0_A, Name:正一郎, 0_B, Key:0_B, Name:清次郎, [[2_C,
Key:2_C, Name:誠三郎]], 2_C, Key:2_C, Name:征史郎,
System.Collections.Generic.KeyNotFoundException: 指定的key在中不存在。
结果是我们可以使用引用类型作为键,但是要注意的是取值是根据引用而不是内容,所以即使内容相同但是引用不同就不会报错。
下面使用相同引用作为键进行尝试。
using System.Linq;
using System.Collections;
using System.Collections.Generic;
public static class Program
{
private class KeyData
{
public int ID { get; set; }
public string Version { get; set; }
public override string ToString()
{
return string.Format( "{0}_{1}", ID, Version );
}
}
private class Parameter
{
public KeyData Key { get; set; }
public string Name { get; set; }
public override string ToString()
{
return string.Format( "Key:{0}, Name:{1}", Key, Name );
}
}
static void Main( string[] args )
{
KeyData keyA = new KeyData() { ID = 0, Version = "A" };
KeyData keyB = new KeyData() { ID = 0, Version = "B" };
KeyData keyC = new KeyData() { ID = 2, Version = "C" };
Parameter[] parameters = new Parameter[]
{
new Parameter() { Key = keyA, Name = "正一郎" },
new Parameter() { Key = keyB, Name = "清次郎" },
new Parameter() { Key = keyC, Name = "誠三郎" },
new Parameter() { Key = keyC, Name = "征史郎" },
};
Dictionary<KeyData, Parameter> dictionary = null;
try
{
dictionary = parameters.ToDictionary( value => value.Key );
}
catch( System.Exception i_exception )
{
System.Console.WriteLine( "{0}", i_exception );
System.Console.ReadKey();
return;
}
System.Console.WriteLine( "parameters:{0}", parameters.Text() );
System.Console.WriteLine( "dictionary:{0}", dictionary.Text() );
System.Console.ReadKey();
}
public static string Text( this IEnumerable i_source )
{
string text = string.Empty;
foreach( var value in i_source )
{
text += string.Format( "[{0}], ", value );
}
return text;
}
}
System.ArgumentException: 相同键的项已添加。
结果会报错。如果删除重复的数据将可以正常运行。
using System.Linq;
using System.Collections;
using System.Collections.Generic;
public static class Program
{
private class KeyData
{
public int ID { get; set; }
public string Version { get; set; }
public override string ToString()
{
return string.Format( "{0}_{1}", ID, Version );
}
}
private class Parameter
{
public KeyData Key { get; set; }
public string Name { get; set; }
public override string ToString()
{
return string.Format( "Key:{0}, Name:{1}", Key, Name );
}
}
static void Main( string[] args )
{
KeyData keyA = new KeyData() { ID = 0, Version = "A" };
KeyData keyB = new KeyData() { ID = 0, Version = "B" };
KeyData keyC = new KeyData() { ID = 2, Version = "C" };
Parameter[] parameters = new Parameter[]
{
new Parameter() { Key = keyA, Name = "正一郎" },
new Parameter() { Key = keyB, Name = "清次郎" },
new Parameter() { Key = keyC, Name = "誠三郎" },
// new Parameter() { Key = keyC, Name = "征史郎" },
};
Dictionary<KeyData, Parameter> dictionary = null;
try
{
dictionary = parameters.ToDictionary( value => value.Key );
}
catch( System.Exception i_exception )
{
System.Console.WriteLine( "{0}", i_exception );
System.Console.ReadKey();
return;
}
System.Console.WriteLine( "parameters:{0}", parameters.Text() );
System.Console.WriteLine( "dictionary:{0}", dictionary.Text() );
try
{
Parameter result = dictionary[ keyC ];
System.Console.WriteLine( "result:{0}", result );
}
catch( System.Exception i_exception )
{
System.Console.WriteLine( "{0}", i_exception );
System.Console.ReadKey();
return;
}
System.Console.ReadKey();
}
public static string Text( this IEnumerable i_source )
{
string text = string.Empty;
foreach( var value in i_source )
{
text += string.Format( "[{0}], ", value );
}
return text;
}
}
parameters:[Key:0_A, Name:正一郎], [Key:0_B, Name:清次郎], [Key:2_C, Name:誠三郎
],
dictionary:0_A, Key:0_A, Name:正一郎, 0_B, Key:0_B, Name:清次郎, [[2_C,
Key:2_C, Name:誠三郎]],
result:Key:2_C, Name:誠三郎
我们了解了将引用类型用作键时的行为,但是也可以让类中属性的值进行比较。
在这种情况下需要使用ToDictionary()的重载。
通过传递继承自IEqualityComparer
的比较类,可以执行自定义的key比较处理。
using System.Linq;
using System.Collections;
using System.Collections.Generic;
public static class Program
{
private class KeyData
{
public int ID { get; set; }
public string Version { get; set; }
public override string ToString()
{
return string.Format( "{0}_{1}", ID, Version );
}
}
private class KeyDataComparer : IEqualityComparer<KeyData>
{
public bool Equals( KeyData i_lhs, KeyData i_rhs )
{
if( i_lhs.ID == i_rhs.ID &&
i_lhs.Version == i_rhs.Version )
{
return true;
}
return false;
}
public int GetHashCode( KeyData i_obj )
{
return i_obj.ID ^ i_obj.Version.GetHashCode();
}
}
private class Parameter
{
public KeyData Key { get; set; }
public string Name { get; set; }
public override string ToString()
{
return string.Format( "Key:{0}, Name:{1}", Key, Name );
}
}
static void Main( string[] args )
{
Parameter[] parameters = new Parameter[]
{
new Parameter() { Key = new KeyData() { ID = 0, Version = "A" }, Name = "正一郎" },
new Parameter() { Key = new KeyData() { ID = 0, Version = "B" }, Name = "清次郎" },
new Parameter() { Key = new KeyData() { ID = 2, Version = "C" }, Name = "誠三郎" },
new Parameter() { Key = new KeyData() { ID = 2, Version = "C" }, Name = "征史郎" },
};
Dictionary<KeyData, Parameter> dictionary = null;
try
{
KeyDataComparer comparer = new KeyDataComparer();
dictionary = parameters.ToDictionary( value => value.Key, comparer );
}
catch( System.Exception i_exception )
{
System.Console.WriteLine( "{0}", i_exception );
System.Console.ReadKey();
return;
}
System.Console.WriteLine( "parameters:{0}", parameters.Text() );
System.Console.WriteLine( "dictionary:{0}", dictionary.Text() );
System.Console.ReadKey();
}
public static string Text( this IEnumerable i_source )
{
string text = string.Empty;
foreach( var value in i_source )
{
text += string.Format( "[{0}], ", value );
}
return text;
}
}
System.ArgumentException: 已经存在相同的键。
ToDictionary()
这时发生了异常。
这里的引用并不相同,但是有两个key的内容是相同的,报错说明方法起了效果。
using System.Linq;
using System.Collections;
using System.Collections.Generic;
public static class Program
{
private class KeyData
{
public int ID { get; set; }
public string Version { get; set; }
public override string ToString()
{
return string.Format( "{0}_{1}", ID, Version );
}
}
private class KeyDataComparer : IEqualityComparer<KeyData>
{
public bool Equals( KeyData i_lhs, KeyData i_rhs )
{
if( i_lhs.ID == i_rhs.ID &&
i_lhs.Version == i_rhs.Version )
{
return true;
}
return false;
}
public int GetHashCode( KeyData i_obj )
{
return i_obj.ID ^ i_obj.Version.GetHashCode();
}
}
private class Parameter
{
public KeyData Key { get; set; }
public string Name { get; set; }
public override string ToString()
{
return string.Format( "Key:{0}, Name:{1}", Key, Name );
}
}
static void Main( string[] args )
{
Parameter[] parameters = new Parameter[]
{
new Parameter() { Key = new KeyData() { ID = 0, Version = "A" }, Name = "正一郎" },
new Parameter() { Key = new KeyData() { ID = 0, Version = "B" }, Name = "清次郎" },
new Parameter() { Key = new KeyData() { ID = 2, Version = "C" }, Name = "誠三郎" },
new Parameter() { Key = new KeyData() { ID = 3, Version = "C" }, Name = "征史郎" },
};
Dictionary<KeyData, Parameter> dictionary = null;
try
{
KeyDataComparer comparer = new KeyDataComparer();
dictionary = parameters.ToDictionary( value => value.Key, comparer );
}
catch( System.Exception i_exception )
{
System.Console.WriteLine( "{0}", i_exception );
System.Console.ReadKey();
return;
}
System.Console.WriteLine( "parameters:{0}", parameters.Text() );
System.Console.WriteLine( "dictionary:{0}", dictionary.Text() );
try
{
Parameter result = dictionary[ new KeyData() { ID = 2, Version = "C" } ];
System.Console.WriteLine( "result:{0}", result );
}
catch( System.Exception i_exception )
{
System.Console.WriteLine( "{0}", i_exception );
System.Console.ReadKey();
return;
}
System.Console.ReadKey();
}
public static string Text( this IEnumerable i_source )
{
string text = string.Empty;
foreach( var value in i_source )
{
text += string.Format( "[{0}], ", value );
}
return text;
}
}
parameters:[Key:0_A, Name:正一郎], [Key:0_B, Name:清次郎], [Key:2_C, Name:誠三郎
], [Key:3_C, Name:征史郎],
dictionary:0_A, Key:0_A, Name:正一郎, 0_B, Key:0_B, Name:清次郎, [[2_C,
Key:2_C, Name:誠三郎]], 3_C, Key:3_C, Name:征史郎,
result:Key:2_C, Name:誠三郎
即使将引用类型用作key,也可以用这种方法根据内容进行取值比较。
上一篇: 轻松掌握 LINQ Sum函数的使用方法
下一篇: 使用 LINQ 转换为数组的方法
推荐阅读
-
将YUV420图像转换为BGR图像的方法使用OpenCvSharp实现
-
在uyuv转换为planar yuv420的过程中所使用的方法进行记录
-
使用OpenGL渲染YUV数据的方法
-
解决树莓派4b 64bit上无法使用 Pi Camera V2 的方法
-
在Linux系统下安装和使用软件解压RAR文件的方法
-
Java 8新特性探究(十三)JavaFX 8新特性以及开发2048游戏-JavaFX历史## 跟java在服务器端和web端成绩相比,桌面一直是java的软肋,于是Sun公司在2008年推出JavaFX,弥补桌面软件的缺陷,请看下图JavaFX一路走过来的改进 从上图看出,一开始推出时候,开发者需使用一种名为JavaFX Script的静态的、声明式的编程语言来开发JavaFX应用程序。因为JavaFX Script将会被编译为Java bytecode,程序员可以使用Java代码代替。 JavaFX 2.0之后的版本摒弃了JavaFX Script语言,而作为一个Java API来使用。因此使用JavaFX平台实现的应用程序将直接通过标准Java代码来实现。 JavaFX 2.0 包含非常丰富的 UI 控件、图形和多媒体特性用于简化可视化应用的开发,WebView可直接在应用中嵌入网页;另外 2.0 版本允许使用 FXML 进行 UI 定义,这是一个脚本化基于 XML 的标识语言。 从JDK 7u6开始,JavaFx就与JDK捆绑在一起了,JavaFX团队称,下一个版本将是8.0,目前所有的工作都已经围绕8.0库进行。这是因为JavaFX将捆绑在Java 8中,因此该团队决定跳过几个版本号,迎头赶上Java 8。 ##JavaFx8的新特性 ## ###全新现代主题:Modena 新的Modena主题来替换原来的Caspian主题。不过在Application的start方法中,可以通过setUserAgentStylesheet(STYLESHEET_CASPIAN)来继续使用Caspian主题。 参考http://fxexperience.com/2013/03/modena-theme-update/ ###JavaFX 3D 在JavaFX8中提供了3D图像处理API,包括Shape3D (Box, Cylinder, MeshView, Sphere子类),SubScene, Material, PickResult, LightBase (AmbientLight 和PointLight子类),SceneAntialiasing等。Camera类也得到了更新。从JavaDoc中可以找到更多信息。 ###富文本 强化了富文本的支持 ###TreeTableView ###日期控件DatePicker 增加日期控件 ###用于 CSS 结构的公共 API
-
强制挂载硬盘:一种在Linux中使用mount命令的方法
-
Centos中使用说明:挂载设备(如U盘、光盘、ISO等)的Linux Mount方法
-
在Linux系统下,实现将网盘挂载到本地的方法:使用rclone
-
使用Linux查看磁盘和挂载的方法