自写一个模仿Dictionary与Foreach的实现及心得总结
程序员文章站
2024-03-03 18:02:46
自己写一个类模仿dictionary实现 a、自定义字典类mydic 复制代码 代码如下: using system.collections.generic; namesp...
自己写一个类模仿dictionary实现
a、自定义字典类mydic
using system.collections.generic;
namespace _10_自己写dictionary {
class keyvaluepair {
public keyvaluepair() {
}
public keyvaluepair(string key, string value) {
this.key = key;
this.value = value;
}
private string key;
public string key {
get {
return key;
}
set {
key = value;
}
}
private string value;
public string value {
get {
return this .value;
}
set {
this.value = value ;
}
}
}
class mydic {
list<keyvaluepair > list = new list<keyvaluepair >();
public void add(string key, string value) {
list.add( new keyvaluepair (key, value));
}
public bool containskey(string key) {
bool res = false ;
foreach(keyvaluepair item in list) {
if(item.key == key) {
res = true;
break;
}
}
return res;
}
}
}
b、调用测试
using system;
using system.collections.generic;
using system.diagnostics;
using system.io;
using system.linq;
using system.text;
namespace _10_自己写dictionary {
class program {
static void main(string[] args) {
//dictionary方法实现
dictionary<string , string> dic = new dictionary <string, string>();
string[] filecon = file .readalllines("英汉词典txt格式.txt", encoding.default);
for(int i = 0; i < filecon.count(); i++) {
string[] arr = filecon[i].split(new char[] { ' ' }, stringsplitoptions.removeemptyentries);
if(!dic.containskey(arr[0])) {
dic.add(arr[0], arr[1]);
}
}
stopwatch sw = new stopwatch();
sw.start();
dic.containskey( "china");
sw.stop();
console.writeline(sw.elapsed);//00:00:00:0000055;
//自己写的list实现
mydic mydic = new mydic();
string[] filecon2 = file .readalllines("英汉词典txt格式.txt", encoding.default);
for(int i = 0; i < filecon2.count(); i++) {
string[] arr = filecon2[i].split(new char[] { ' ' }, stringsplitoptions.removeemptyentries);
if(!mydic.containskey(arr[0])) {
mydic.add(arr[0], arr[1]);
}
}
stopwatch sw2 = new stopwatch();
sw2.start();
mydic.containskey( "china");
sw2.stop();
console.writeline(sw2.elapsed);//00:00:00:0001287;慢了多少倍!!! 因为dictionary比list多了字典目录
console.read();
}
}
}
b中测试结果显示自己模仿的没有.net framework提供的快 为什么呢?
答:dictionary中有一个存储键值对的区域,这个区域的每个存储单元有地址编号,根据hashcode算法,计算key的值的键值对应该存储的地址,将键值对放入指定的地址即可。查找的时候首先计算key的地址,就可以找到数据了。根据key找房间号,而不是逐个房间找。(*)或者说:当把一个kvp,采用一个固定算法(散列算法)根据key来计算这个kvp存放的地址。取的时候也是根据要找的key可以快速算出kvp存放的地址。
面试题中经常会问foreach实现了什么接口这个问题很好回答,那我们能不能自己模仿实现foreach呢?
c、foreach内部原理:ienumerable接口 自己实现ienumerable
using system.collections;//引入ienumerable所在命名空间
namespace ienumerater {
class mylist : ienumerable {//实现接口ienumerable 它就一个ienumerator声明枚举器的方法
arraylist ary = new arraylist();
public void add(string name) {
ary.add(name);
}
//自己写索引器 形式类似属性 作用类似枚举 方便快捷的方式 访问集合中的元素
public string this[ int index] {//int类型
get {
return ary[index].tostring();
} //index>ary.count时超出索引界限
//set { }
}
public int this[ string name] {//string类型 通过name查找索引 参数类型自己决定 返回类型自己决定
get {
for(int i = 0; i < ary.count; i++) {
if(ary[i] == name) {
return i;
}
}
return -1;
}
}
public ienumerator getenumerator() {//ienumerator f12跳转定义这里可以发现foreach只允许读取数据,而不能修改数据
for(int i = 0; i < ary.count; i++) {
yield return ary[i].tostring();// yield关键字 可以看到 实现ienumerator(枚举器)接口中movenext(指向下一条)方法 和current(获取当前元素 因为只有get 所以可以理解为什么foreach不能修改值的原因了) 以及reset重置索引
}
}
}
}
d、调用自己的ienumerable
using system;
namespace ienumerater {
class program {
static void main(string[] args) {
//自己写一个类 实现了ienumerable接口的getenumerator()方法 就可以实现foreach的操作
mylist mylist = new mylist();
mylist.add( "wanghao");//调用自己的add(string)方法
mylist.add( "nihao");
mylist.add( "buhao");
console.writeline(mylist[1]);//使用自己的索引
console.writeline(mylist["nihao" ].tostring());
foreach(string item in mylist) {
console.writeline(item);
//item = "hello"; 不能使用foreach改变值
}
console.read();
}
}
}
总结:
如果一个类进行foreach的话,该类必须实现ienumerable,集合要支持foreach方式的遍历,必须实现ienumerable接口(还要以某种方式返回实现了ienumerator 的对象)
a、自定义字典类mydic
复制代码 代码如下:
using system.collections.generic;
namespace _10_自己写dictionary {
class keyvaluepair {
public keyvaluepair() {
}
public keyvaluepair(string key, string value) {
this.key = key;
this.value = value;
}
private string key;
public string key {
get {
return key;
}
set {
key = value;
}
}
private string value;
public string value {
get {
return this .value;
}
set {
this.value = value ;
}
}
}
class mydic {
list<keyvaluepair > list = new list<keyvaluepair >();
public void add(string key, string value) {
list.add( new keyvaluepair (key, value));
}
public bool containskey(string key) {
bool res = false ;
foreach(keyvaluepair item in list) {
if(item.key == key) {
res = true;
break;
}
}
return res;
}
}
}
b、调用测试
复制代码 代码如下:
using system;
using system.collections.generic;
using system.diagnostics;
using system.io;
using system.linq;
using system.text;
namespace _10_自己写dictionary {
class program {
static void main(string[] args) {
//dictionary方法实现
dictionary<string , string> dic = new dictionary <string, string>();
string[] filecon = file .readalllines("英汉词典txt格式.txt", encoding.default);
for(int i = 0; i < filecon.count(); i++) {
string[] arr = filecon[i].split(new char[] { ' ' }, stringsplitoptions.removeemptyentries);
if(!dic.containskey(arr[0])) {
dic.add(arr[0], arr[1]);
}
}
stopwatch sw = new stopwatch();
sw.start();
dic.containskey( "china");
sw.stop();
console.writeline(sw.elapsed);//00:00:00:0000055;
//自己写的list实现
mydic mydic = new mydic();
string[] filecon2 = file .readalllines("英汉词典txt格式.txt", encoding.default);
for(int i = 0; i < filecon2.count(); i++) {
string[] arr = filecon2[i].split(new char[] { ' ' }, stringsplitoptions.removeemptyentries);
if(!mydic.containskey(arr[0])) {
mydic.add(arr[0], arr[1]);
}
}
stopwatch sw2 = new stopwatch();
sw2.start();
mydic.containskey( "china");
sw2.stop();
console.writeline(sw2.elapsed);//00:00:00:0001287;慢了多少倍!!! 因为dictionary比list多了字典目录
console.read();
}
}
}
b中测试结果显示自己模仿的没有.net framework提供的快 为什么呢?
答:dictionary中有一个存储键值对的区域,这个区域的每个存储单元有地址编号,根据hashcode算法,计算key的值的键值对应该存储的地址,将键值对放入指定的地址即可。查找的时候首先计算key的地址,就可以找到数据了。根据key找房间号,而不是逐个房间找。(*)或者说:当把一个kvp,采用一个固定算法(散列算法)根据key来计算这个kvp存放的地址。取的时候也是根据要找的key可以快速算出kvp存放的地址。
面试题中经常会问foreach实现了什么接口这个问题很好回答,那我们能不能自己模仿实现foreach呢?
c、foreach内部原理:ienumerable接口 自己实现ienumerable
复制代码 代码如下:
using system.collections;//引入ienumerable所在命名空间
namespace ienumerater {
class mylist : ienumerable {//实现接口ienumerable 它就一个ienumerator声明枚举器的方法
arraylist ary = new arraylist();
public void add(string name) {
ary.add(name);
}
//自己写索引器 形式类似属性 作用类似枚举 方便快捷的方式 访问集合中的元素
public string this[ int index] {//int类型
get {
return ary[index].tostring();
} //index>ary.count时超出索引界限
//set { }
}
public int this[ string name] {//string类型 通过name查找索引 参数类型自己决定 返回类型自己决定
get {
for(int i = 0; i < ary.count; i++) {
if(ary[i] == name) {
return i;
}
}
return -1;
}
}
public ienumerator getenumerator() {//ienumerator f12跳转定义这里可以发现foreach只允许读取数据,而不能修改数据
for(int i = 0; i < ary.count; i++) {
yield return ary[i].tostring();// yield关键字 可以看到 实现ienumerator(枚举器)接口中movenext(指向下一条)方法 和current(获取当前元素 因为只有get 所以可以理解为什么foreach不能修改值的原因了) 以及reset重置索引
}
}
}
}
d、调用自己的ienumerable
复制代码 代码如下:
using system;
namespace ienumerater {
class program {
static void main(string[] args) {
//自己写一个类 实现了ienumerable接口的getenumerator()方法 就可以实现foreach的操作
mylist mylist = new mylist();
mylist.add( "wanghao");//调用自己的add(string)方法
mylist.add( "nihao");
mylist.add( "buhao");
console.writeline(mylist[1]);//使用自己的索引
console.writeline(mylist["nihao" ].tostring());
foreach(string item in mylist) {
console.writeline(item);
//item = "hello"; 不能使用foreach改变值
}
console.read();
}
}
}
总结:
如果一个类进行foreach的话,该类必须实现ienumerable,集合要支持foreach方式的遍历,必须实现ienumerable接口(还要以某种方式返回实现了ienumerator 的对象)