找回密码
 用户注册

QQ登录

只需一步,快速开始

查看: 4300|回复: 0

集合,没那么简单

[复制链接]
发表于 2012-1-14 10:27:46 | 显示全部楼层 |阅读模式
集合,没那么简单
         好久都没有碰过前端页面的东西了,前几天做一个下拉列表的动态增删,是由js在前台操作select的option来实现的,但是奇怪的事,有的时候不能正确的清空列表的所有选项!本来觉得没有什么可以记的,但是细细咀嚼,还是有必要的!
         先贴出我实现清空列表的代码     
[javascript] view plaincopyprint?


  • //删除列表的所有选项   
  • function clearListBox(listBox) {  
  •     for (var i = 0; i < listBox.length; i++) {  
  •         removeListBoxOption(listBox,i);  
  •     };  
  • };  
  •   
  • //删除给定列表的某个选项   
  • function removeListBoxOption(listBox,index) {  
  •     listBox.remove(index);  
  • };  


         如果你没有一眼看出问题所在,那么我想你可能是foreach的忠实粉丝;其实集合也好,数组也罢,虽然很多时候是作为容器来使用,其实他们没有那么简单;

很多时候他们是我们缓存昂贵资源的法宝,如果你对性能要求比较高,那么很多时候你的开发生活不能缺少它!
从数据结构的角度来看,集合可以实现各种复杂的数据结构,.net中实现的字典、列表等等,都是基于数组实现的;同时不同的数据结构,自然遍历和增删的性能是不一样的,不过我们不用担心,这些微软的类库开发人员都为我们考虑了!不得不说微软为了提高开发人员的工作效率,替我们做了很多的工作;那能不能说,缺少数据结构和算法的web开发程序猿,就不是真正的程序员呢?这个留待以后谈;

从更广义上来说,变量是承载某种类型数值的集合,原始类型的变量直接承载原始类型的内容;复合类型变量本质上承载各种原始类型的变量的集合,当然其也可以有复合类型的成员,当然类除了定义其数据,也定义了其行为来操作修改这些数据;还有我们平时使用的数据库二维关系表……
         以上纯属自己开发中的一些体会,有什么不对的地方,欢迎大家批评斧正;今天我们要解决的问题是列表集合的遍历删除问题;那么我们先来看看集合的遍历中一些容易被忽略的细节;
         Foreach的遍历,对获取集合的方法只会调用一次public class Test
  1. {
  2.     //集合字段
  3.     private IList<int> collection = new List<int>() { 1, 2, 3, 4, 5, 6 };
  4.     //集合字段对应属性
  5.     public IList<int> Collection
  6.     {
  7.         get
  8.         {
  9.             Console.WriteLine("获取了集合");
  10.             return this.collection;
  11.         }
  12.     }
  13.     /// <summary>
  14.     /// 测试foreach
  15.     /// </summary>
  16.     public void TestForeach()
  17.     {
  18.         foreach (int item in this.Collection)
  19.         {
  20.             int a = item;
  21.         }
  22.     }
  23. }
复制代码
         For的正向遍历,每次我们都需要都会调用获取集合的方法,并且每次都要访问集合的长度public class Test
  1.          {
  2.     //集合字段
  3.     private IList<int> collection = new List<int>() { 1, 2, 3, 4, 5, 6 };
  4.     //集合字段对应属性
  5.     public IList<int> Collection
  6.     {
  7.         get
  8.         {
  9.             Console.WriteLine("获取了集合");
  10.             return this.collection;
  11.         }
  12.     }
  13.     /// <summary>
  14.     /// for正向遍历集合
  15.     /// </summary>
  16.     public void TestForForward()
  17.     {
  18.         for (int i = 0; i < this.Collection.Count; i++)
  19.         {
  20.             int a = this.Collection[i];
  21.         }
  22.     }
  23. }
复制代码
         For的反向遍历,只有第一次遍历的时候调用获取集合的方法public class Test
  1.          {
  2.     //集合字段
  3.     private IList<int> collection = new List<int>() { 1, 2, 3, 4, 5, 6 };
  4.     //集合字段对应属性
  5.     public IList<int> Collection
  6.     {
  7.         get
  8.         {
  9.             Console.WriteLine("获取了集合");
  10.             return this.collection;
  11.         }
  12.     }
  13.     /// <summary>
  14.     /// for反向遍历集合
  15.     /// </summary>
  16.     public void TestForReverse()
  17.     {
  18.         for (int i = this.Collection.Count - 1; i > -1; i--)
  19.         {
  20.             int a = this.Collection[i];
  21.         }
  22.     }
  23. }
复制代码
          虽然这些细节会影响集合遍历的性能,但是这些并不是今天我们要关注的;在.net里他们的性能差异怎么样,js中差别怎么样,如果您感兴趣可以自己测试;
         Foreach的最终的实现是通过链表实现的,我想着也就是为什么我们遍历集合的时候,不能对其进行删除的原因吧!使用for遍历,我们是通过数组下表直接访问,我们可以在遍历的时候删除元素,但是每次删除元素后,集合的length就会变化;
         现在回过头来看看删除列表选项的代码,显然其问题就在每次遍历都要重新获取集合的length;那么我们可以这样修改
         For//使用for实现删除列表的所有选项
  1. function clearListBox(listBox) {
  2.     for (var i = 0; i < listBox.length; ) {
  3.         removeListBoxOption(listBox,i);
  4.     };
  5. };
  6.          While//while实现删除列表的所有选项
  7. function clearListBox(listBox) {
  8.     while (listBox.length > -1) {
  9.         removeListBoxOption(listBox,0);
  10.     };
  11. };
复制代码
          现在我们解决了删除列表的所有选项!好像没有什么问题了,那么现在我们需要将源列表中一些选项移动到目的列表中,这个时候我们怎么做呢?这个时候我们需要一个集合

//将源列表中选中的选项转移到目的列表中
  1. function moveOption(listBoxSou, listBoxDes) {
  2.     var selectOptionArray = getOptionInfo(listBoxSou);
  3.     removeListBoxOptions(listBoxSou, selectOptionArray);
  4.     addListBoxOptions(listBoxDes,selectOptionArray);
  5. };
  6. //获取列表的选中项的信息
  7. function getOptionInfo(listBox) {
  8.     var array = new Array();
  9.     var options = listBox.options;
  10.     for (var i = 0; i < listBox.length; i++) {
  11.         var option=options[i];
  12.         if (option.selected) {
  13.             array.push({"text":option.text,"value":option.value});
  14.         };
  15.     };
  16.     return array;
  17. };
  18. //在给定的列表中删除给定的选项
  19. function removeListBoxOptions(listBox, array) {
  20.     var options = listBox.options;
  21.     for (var i = 0; i < array.length; i++) {
  22.         var delOptionInfo=array[i];
  23.         for (var j = 0; j < listBox.length; j++) {
  24.             if (options[j].value == delOptionInfo.value) {
  25.                 removeListBoxOption(listBox, j);
  26.                 break;
  27.             }
  28.         };
  29.     };
  30. };
  31. //向指定列表中添加给定的选项
  32. function addListBoxOptions(listBox, array) {
  33.     for (var i = 0; i < array.length; i++) {
  34.         var optionInfo = array[i];
  35.         addListBoxOption(listBox,optionInfo.text,optionInfo.value);
  36.     };
  37. };
  38. //向指定列表添加选项
  39. function addListBoxOption(listBox, text, value) {
  40.     var option = document.createElement('option');
  41.     option.value = value;
  42.     option.text = text;
  43.     listBox.add(option);
  44. };
复制代码
          由于我们的功能实现的比较复杂,同时涉及的数据量比较大,同时提供可以搜索列表框中的选项,同时涉及到多个列表并且他们之间是有关联关系的,所以我自己实现了一个简单的字典集合,其功能主要是缓存列表数据源,并没有优化实现遍历的算法,黏贴部分代码,感兴趣可以看一下<script type="text/javascript" src=http://blog.csdn.net/"Scripts/jquery-1.4.1.js"></script><script type="text/javascript">
  1.     //源列表初始化字符串
  2.     var initStr = "1,北京~2,上海~3,天津~4,河北~5,山东~6,河南~7,山西";
  3.     //初始化字符串记录间的分隔符
  4.     var recordSep = "~";
  5.     //编号和名称间的分隔符
  6.     var innerSep = ",";
  7.     //源列表id
  8.     var listBoxSouId = "listBoxSou";
  9.     //目标列表id
  10.     var listBoxDesId = "listBoxDes";
  11.     var listBoxSou = null;
  12.     var listBoxDes = null;
  13.     //页面初始化
  14.     function pageLoad() {debugger;
  15.         //初始化变量
  16.         listBoxSou = $("#" + listBoxSouId).get(0);
  17.         listBoxDes = $("#" + listBoxDesId).get(0);
  18.         var listDataSourceType = "string";
  19.         var dataSource = getDataSource(listDataSourceType);
  20.         bindData(listBoxSou,dataSource);
  21.     }
  22.     //可以有多种获取数据源的方式,也可以有多种承载数据源的介质
  23.     function getDataSource(dataSourceType) {
  24.         if (dataSourceType == "string") {
  25.             return getStringDataSource();
  26.         }
  27.         return new Dictionary();
  28.     }
  29.     //获取字符串格式的列表数据源
  30.     function getStringDataSource() {
  31.         var dictionary = new Dictionary();
  32.         var recordArray = initStr.split(recordSep);
  33.         $.each(recordArray, function (index, record) {
  34.             var idNameArray = record.split(innerSep);
  35.             dictionary.add(idNameArray[0], idNameArray[1]);           
  36.         });
  37.         return dictionary;
  38.     };
  39.     //为列表绑定数据源
  40.     function bindData(listBox, dataSource) {
  41.         clearListBox(listBox);
  42.         dataSource.each(function (index, item) {
  43.             addOption(listBox, item.key, item.value);
  44.         });
  45.     };
  46.     //向指定列表添加选项
  47.     function addOption(listBox,text,value) {
  48.         var option = document.createElement('option');
  49.         option.value = value;
  50.         option.text = text;
  51.         listBox.add(option);
  52.     };
  53.     //清空列表的所有选项
  54.     function clearListBox(listBox) {
  55.         while (listBox.length > 0) {
  56.             removeOption(listBox,0);
  57.         }
  58.     };
  59.     //删除指定列表的指定项
  60.     function removeOption(listBox, index) {
  61.         listBox.remove(index);
  62.     };
  63.     $(document).ready(pageLoad);
  64.     function KeyValuePair(key, value) {
  65.         this.key = key;
  66.         this.value = value;
  67.     };
  68.     KeyValuePair.prototype.key = null;
  69.     KeyValuePair.prototype.value = null;
  70.    
  71.    
  72.     function Dictionary() {
  73.         this.clear();
  74.     };
  75.    
  76.     Dictionary.prototype.keyValuePairs = null;
  77.     Dictionary.prototype.length = 0;
  78.     Dictionary.prototype.add = function (key, value) {
  79.         this.keyValuePairs.push(new KeyValuePair(key, value));
  80.         ++this.length;
  81.     };
  82.     Dictionary.prototype.remove = function (key) {
  83.         for (var i = 0; i < this.length; i++) {
  84.             if (this.keyValuePairs[i].key == key) {
  85.                 this.keyValuePairs.splice(i, 0);
  86.                 --this.length;
  87.                 break;
  88.             }
  89.         }
  90.     };
  91.     Dictionary.prototype.get = function (key) {
  92.         for (var i = 0; i < this.length; i++) {
  93.             if (this.keyValuePairs[i].key == key) {
  94.                 return this.keyValuePairs[i].value;
  95.                 break;
  96.             }
  97.         }
  98.     };
  99.     Dictionary.prototype.getKey = function (value) {
  100.         for (var i = 0; i < this.length; i++) {
  101.             if (this.keyValuePairs[i].value == value) {
  102.                 return this.keyValuePairs[i].key;
  103.                 break;
  104.             }
  105.         }
  106.     };
  107.     Dictionary.prototype.clear = function () {
  108.         this.keyValuePairs = new Array();
  109.         this.length = 0;
  110.     };
  111.     Dictionary.prototype.contains = function (key) {
  112.         if (this.get(key)) {
  113.             return true;
  114.         }
  115.         return false;
  116.     };
  117.     Dictionary.prototype.each = function (callback) {
  118.         if (callback != undefined && callback) {
  119.             for (var i = 0; i < this.length; i++) {
  120.                 callback.call(window, i, this.keyValuePairs[i]);
  121.             }
  122.         }
  123.     };
  124.    
  125. </script>
复制代码
您需要登录后才可以回帖 登录 | 用户注册

本版积分规则

Archiver|手机版|小黑屋|ACE Developer ( 京ICP备06055248号 )

GMT+8, 2024-11-21 23:17 , Processed in 0.019062 second(s), 6 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表