集合,没那么简单
来源:互联网 发布:加州大学分校 知乎 编辑:程序博客网 时间:2024/05/11 05:24
集合,没那么简单
好久都没有碰过前端页面的东西了,前几天做一个下拉列表的动态增删,是由js在前台操作select的option来实现的,但是奇怪的事,有的时候不能正确的清空列表的所有选项!本来觉得没有什么可以记的,但是细细咀嚼,还是有必要的!
先贴出我实现清空列表的代码
//删除列表的所有选项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{ //集合字段 private IList<int> collection = new List<int>() { 1, 2, 3, 4, 5, 6 }; //集合字段对应属性 public IList<int> Collection { get { Console.WriteLine("获取了集合"); return this.collection; } } /// <summary> /// 测试foreach /// </summary> public void TestForeach() { foreach (int item in this.Collection) { int a = item; } }}
For的正向遍历,每次我们都需要都会调用获取集合的方法,并且每次都要访问集合的长度
public class Test{ //集合字段 private IList<int> collection = new List<int>() { 1, 2, 3, 4, 5, 6 }; //集合字段对应属性 public IList<int> Collection { get { Console.WriteLine("获取了集合"); return this.collection; } } /// <summary> /// for正向遍历集合 /// </summary> public void TestForForward() { for (int i = 0; i < this.Collection.Count; i++) { int a = this.Collection[i]; } }}
For的反向遍历,只有第一次遍历的时候调用获取集合的方法
public class Test{ //集合字段 private IList<int> collection = new List<int>() { 1, 2, 3, 4, 5, 6 }; //集合字段对应属性 public IList<int> Collection { get { Console.WriteLine("获取了集合"); return this.collection; } } /// <summary> /// for反向遍历集合 /// </summary> public void TestForReverse() { for (int i = this.Collection.Count - 1; i > -1; i--) { int a = this.Collection[i]; } }}
虽然这些细节会影响集合遍历的性能,但是这些并不是今天我们要关注的;在.net里他们的性能差异怎么样,js中差别怎么样,如果您感兴趣可以自己测试;
Foreach的最终的实现是通过链表实现的,我想着也就是为什么我们遍历集合的时候,不能对其进行删除的原因吧!使用for遍历,我们是通过数组下表直接访问,我们可以在遍历的时候删除元素,但是每次删除元素后,集合的length就会变化;
现在回过头来看看删除列表选项的代码,显然其问题就在每次遍历都要重新获取集合的length;那么我们可以这样修改
For
//使用for实现删除列表的所有选项function clearListBox(listBox) { for (var i = 0; i < listBox.length; ) { removeListBoxOption(listBox,i); };};
While
//while实现删除列表的所有选项function clearListBox(listBox) { while (listBox.length > -1) { removeListBoxOption(listBox,0); };};
现在我们解决了删除列表的所有选项!好像没有什么问题了,那么现在我们需要将源列表中一些选项移动到目的列表中,这个时候我们怎么做呢?这个时候我们需要一个集合
//将源列表中选中的选项转移到目的列表中function moveOption(listBoxSou, listBoxDes) { var selectOptionArray = getOptionInfo(listBoxSou); removeListBoxOptions(listBoxSou, selectOptionArray); addListBoxOptions(listBoxDes,selectOptionArray);};//获取列表的选中项的信息function getOptionInfo(listBox) { var array = new Array(); var options = listBox.options; for (var i = 0; i < listBox.length; i++) { var option=options[i]; if (option.selected) { array.push({"text":option.text,"value":option.value}); }; }; return array;};//在给定的列表中删除给定的选项function removeListBoxOptions(listBox, array) { var options = listBox.options; for (var i = 0; i < array.length; i++) { var delOptionInfo=array[i]; for (var j = 0; j < listBox.length; j++) { if (options[j].value == delOptionInfo.value) { removeListBoxOption(listBox, j); break; } }; };};//向指定列表中添加给定的选项function addListBoxOptions(listBox, array) { for (var i = 0; i < array.length; i++) { var optionInfo = array[i]; addListBoxOption(listBox,optionInfo.text,optionInfo.value); };};//向指定列表添加选项function addListBoxOption(listBox, text, value) { var option = document.createElement('option'); option.value = value; option.text = text; listBox.add(option);};
由于我们的功能实现的比较复杂,同时涉及的数据量比较大,同时提供可以搜索列表框中的选项,同时涉及到多个列表并且他们之间是有关联关系的,所以我自己实现了一个简单的字典集合,其功能主要是缓存列表数据源,并没有优化实现遍历的算法,黏贴部分代码,感兴趣可以看一下
<script type="text/javascript" src="Scripts/jquery-1.4.1.js"></script><script type="text/javascript"> //源列表初始化字符串 var initStr = "1,北京~2,上海~3,天津~4,河北~5,山东~6,河南~7,山西"; //初始化字符串记录间的分隔符 var recordSep = "~"; //编号和名称间的分隔符 var innerSep = ","; //源列表id var listBoxSouId = "listBoxSou"; //目标列表id var listBoxDesId = "listBoxDes"; var listBoxSou = null; var listBoxDes = null; //页面初始化 function pageLoad() {debugger; //初始化变量 listBoxSou = $("#" + listBoxSouId).get(0); listBoxDes = $("#" + listBoxDesId).get(0); var listDataSourceType = "string"; var dataSource = getDataSource(listDataSourceType); bindData(listBoxSou,dataSource); } //可以有多种获取数据源的方式,也可以有多种承载数据源的介质 function getDataSource(dataSourceType) { if (dataSourceType == "string") { return getStringDataSource(); } return new Dictionary(); } //获取字符串格式的列表数据源 function getStringDataSource() { var dictionary = new Dictionary(); var recordArray = initStr.split(recordSep); $.each(recordArray, function (index, record) { var idNameArray = record.split(innerSep); dictionary.add(idNameArray[0], idNameArray[1]); }); return dictionary; }; //为列表绑定数据源 function bindData(listBox, dataSource) { clearListBox(listBox); dataSource.each(function (index, item) { addOption(listBox, item.key, item.value); }); }; //向指定列表添加选项 function addOption(listBox,text,value) { var option = document.createElement('option'); option.value = value; option.text = text; listBox.add(option); }; //清空列表的所有选项 function clearListBox(listBox) { while (listBox.length > 0) { removeOption(listBox,0); } }; //删除指定列表的指定项 function removeOption(listBox, index) { listBox.remove(index); }; $(document).ready(pageLoad); function KeyValuePair(key, value) { this.key = key; this.value = value; }; KeyValuePair.prototype.key = null; KeyValuePair.prototype.value = null; function Dictionary() { this.clear(); }; Dictionary.prototype.keyValuePairs = null; Dictionary.prototype.length = 0; Dictionary.prototype.add = function (key, value) { this.keyValuePairs.push(new KeyValuePair(key, value)); ++this.length; }; Dictionary.prototype.remove = function (key) { for (var i = 0; i < this.length; i++) { if (this.keyValuePairs[i].key == key) { this.keyValuePairs.splice(i, 0); --this.length; break; } } }; Dictionary.prototype.get = function (key) { for (var i = 0; i < this.length; i++) { if (this.keyValuePairs[i].key == key) { return this.keyValuePairs[i].value; break; } } }; Dictionary.prototype.getKey = function (value) { for (var i = 0; i < this.length; i++) { if (this.keyValuePairs[i].value == value) { return this.keyValuePairs[i].key; break; } } }; Dictionary.prototype.clear = function () { this.keyValuePairs = new Array(); this.length = 0; }; Dictionary.prototype.contains = function (key) { if (this.get(key)) { return true; } return false; }; Dictionary.prototype.each = function (callback) { if (callback != undefined && callback) { for (var i = 0; i < this.length; i++) { callback.call(window, i, this.keyValuePairs[i]); } } }; </script>
- 集合,没那么简单
- 没那么简单,没那么困难
- 《没那么简单》-黄小琥
- ~没那么简单~
- 没那么简单
- 没那么简单
- 没那么简单
- 没那么简单
- 这个,没那么简单
- BroadcastReceiver,没那么简单!
- container_of, 没那么简单
- 创业没那么简单
- 没那么简单
- super 没那么简单
- 没那么简单
- “简单没那么容易做到”
- 时间管理,没那么简单!!!
- 辞职创业?没那么简单
- 400 - Unix ls
- android模拟器上调试带共享库(*.so)的程序
- CSS中Zoom属性的一些介绍
- Git基本使用
- 经典书籍
- 集合,没那么简单
- 谈下自己了解的云计算
- SQL Server COUNT() 和SUM()的使用方法
- 用rand()和srand()产生为随机数的方法总结
- java 网络编程 TCP
- StatusBarManager 类用于在程序中控制状态栏.
- ubuntu 计事
- 路由加速配置
- uc第三天系统调用