随机产生20个单词
一、问题来源:
老师给了一份专业单词word,说第二天要全背下来。错了就五十遍啊五十遍。
然后,有人提出要做一个产生随机单词的Demo,来测试自己。
老师表示呵呵,做出来的就可以不用听写。
顿时,我就表示,是可忍,孰不可忍啊。这是在侮辱我们啊。这票我干了,不能让人看低了。我这么做绝对不是为了逃避五十遍,真的。
二、问题思考:
写Demo之前,先思考一下这个程序的逻辑。
首先,我要导入数据,然后将数据转化为便于使用的数据类型。
导入数据方面,我选择了直接复制,然后以字符串的形式保存在一个数组内。当然,如果在实际使用中更方便。直接将服务器端传输的JSON数据转化就OK了。
数据转换方面,我原本想着使用正则去识别。然而我发现WebStorm直接将空格和回车都转化出来了。那就方便了。建立一个函数trans来将字符串a转化为我们需要的Object数组。当然你也可以转化为字符串数组。但是我认为转化为Object数组后更易于理解与使用,也更符合逻辑。
在这之后就是从数组中挑选20个Object出来,显示出来。这涉及到两个问题,首先如何挑选,其次如何显示。
显示问题,太简单了。直接做一个按钮的监听事件,每一次点击都重新选取。记得每次选取前要初始化,即可。
下面就是这个Demo的最大看点,如何选取20不重复的随机数。当然这个问题,解决方法很多。常用的办法有这两种。(假设源数据数量为count)
一、建立一个大小为count的数组a,存储的数据从min到max。然后,利用random()方法产生一个随机数randomnumber,从数组a中抽取a[randomnumber],保存在数组b中。之后每次抽取随机数randomnumber,都在数组b中遍历,是否存在。不过不存在就添加。直到数组b的length达到20。
二、建立一个大小为count的数组a,存储的数据从min到max。然后,利用random()方法产生一个随机数randomnumber,从数组a中抽取a[randomnumber],保存在数组b中,同时将数组a中的a[randomnumber]删除。直到数组b的length达到20。
上述方法中有一些JS才有的方法,可以加快效率。比如数组的Indexof()方法来查找元素等等。
当然,我的方法和上面有所不同。(否则我也不会这么膨胀)方法如下:
建立一个大小为count的数组a,存储的数据从min到max。然后,利用random()方法产生一个随机数randomnumber,从数组a中抽取a[randomnumber],保存在数组b中。与此同时,令数组c中c[randomnumber]=1。这样每次产生随机数后,只有在if(!c[randomnumber])条件成立,才向数组b内添加a[randomnumber],同时,数组计数器+1。
虽然描写看起来更麻烦一些,但是这样就避免了查询已产生随机数的循环遍历的资源消耗。
三、完整代码:
1 <!DOCTYPE html> 2 <html lang="zh-cn"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>random-words(20)</title> 6 <script src="jquery-v1.12.4.js"></script> 7 <script> 8 let a = "continue\t继续。程序设计中跳出当次循环的关键字。\n" + 9 "break\t终止。程序设计中终止循环的关键字。\n" + 10 "next\t下一个。\n" + 11 "function\t函数。程序设计中定义函数的关键字。\n" + 12 "return\t返回。程序设计中函数返回数据的关键字。\n" + 13 "true\t真的\n" + 14 "false\t假的\n" + 15 "var\t定义变量关键字。\n" + 16 "int\t整型。\n" + 17 "boolean\t布尔型。\n" + 18 "float\t浮点型数值。\n" + 19 "double\t双精度数值。\n" + 20 "class\t类。定义类的关键字。\n" + 21 "public\t公有的。\n" + 22 "private\t私有的。\n" + 23 "static\t静态的。\n" + 24 "super\t超级。代指面向对象编程中父级类。\n" + 25 "this\t这个。一般指当前对象。\n" + 26 "window\t窗口。DOM中的浏览器窗口对象。\n" + 27 "document\t文档。DOM中的文档对象。\n" + 28 "width\t宽度\n" + 29 "height\t高度\n" + 30 "first\t第一个。\n" + 31 "last\t最后的。\n" + 32 "parent\t父亲,父级。\n" + 33 "append\t追加。\n" + 34 "before\t之前\n" + 35 "after\t之后\n" + 36 "focus\t焦点。CSS中的伪类名称,常用于设计控件获得焦点时的效果\n" + 37 "hover\t悬停。CSS中的伪类名称,常用于设计鼠标经过效果\n" + 38 "select\t选择。HTML中的下拉框标签名\n" + 39 "checkbox\t复选框\n" + 40 "submit\t提交\n" + 41 "reset\t重置\n" + 42 "click\t单击事件\n" + 43 "keyup\t键盘松开事件\n" + 44 "keydown\t键盘按下事件\n" + 45 "mouseup\t鼠标松开或者弹起事件\n" + 46 "mousedown\t鼠标按下事件\n" + 47 "empty\t空的\n" + 48 "remove\t移除\n" + 49 "array\t数组\n" + 50 "show\t显示\n" + 51 "hide\t隐藏\n" + 52 "animate\t动画。jQuery中的自定义动画方法。\n" + 53 "event\t事件\n" + 54 "replace\t替换\n" + 55 "join\t数组方法之一,将元素合并成字符串\n" + 56 "split\t字符串方法之一,将字符串切割成数组\n" + 57 "splice\t数组方法之一,可增、删、改元素\n" + 58 "underline\t下划线\n" + 59 "fixed\t定位元素的样式属性值之一,固定定位\n" + 60 "position\t定位元素的样式属性名\n" + 61 "align\t对齐方式\n" + 62 "background\t设置元素背景的属性名\n" + 63 "display\t显示\n" + 64 "solid\t边框线条样式值之一,实线类型\n" + 65 "clear\t清除,清理\n" + 66 "element\t元素\n" + 67 "home\t家,或首页\n" + 68 "middle\t中间的,垂直居中样式值\n" + 69 "center\t水平居中\n" + 70 "button\t按钮\n" + 71 "hidden\t被隐藏的\n" + 72 "important\t重要的,提升样式的优先级\n" + 73 "margin\t元素外边距属性名\n" + 74 "object\t对象\n" + 75 "transform\t变换,设置CSS3变换的样式属性名称\n" + 76 "relative\t相对的,定位属性值之一的相对定位\n" + 77 "arguments\t参数集合,LESS混合中或者JS函数中代表参数集合\n" + 78 "method\t方法\n" + 79 "action\t动作,表单form的属性之一\n" + 80 "number\t数字或数值,JavaScript中的数据类型之一\n" + 81 "translate\t平移,用于设置元素的位置\n" + 82 "padding\t元素内间距属性名\n" + 83 "source\t来源\n" + 84 "control\t控制或控件\n" + 85 "video\t视频,H5新增播放视频的标签名\n" + 86 "default\t默认的,缺省的\n" + 87 "container\t容器\n" + 88 "content\t内容\n" + 89 "textarea\t文本输入域的标签名称\n" + 90 "current\t当前的\n" + 91 "visited\t已经访问过的\n" + 92 "inner\t内部的\n" + 93 "outer\t外部的\n" + 94 "client\t客户端\n" + 95 "location\t位置,定位\n" + 96 "instance\t实例\n" + 97 "prototype\t原型对象\n" + 98 "property\t属性\n" + 99 "constructor\t构造函数\n" + 100 "innerWidth\t内部宽度\n" + 101 "prepend\t在元素内部前置插入元素\n" + 102 "trigger\t主动触发事件\n" + 103 "triggerHandler\t主动触发事件,但不触发浏览器默认事件\n" + 104 "fadeIn\t淡入动画方法\n" + 105 "fadeOut\t淡出动画方法\n" + 106 "currentTarget\t总是指向事件监听目标对象\n" + 107 "focusin\t元素获得焦点时触发事件的方法\n"; 108 </script> 109 <style> 110 .container{ 111 border : 5px solid #333333; 112 padding : 30px; 113 background : sandybrown; 114 } 115 .top-container{ 116 width: 100%; 117 height: 50px; 118 } 119 .headtitle{ 120 display: block; 121 float: left; 122 position: relative; 123 width: 300px; 124 font-size: 24px; 125 text-align : center; 126 } 127 .ebuttom{ 128 display: block; 129 float: left; 130 top:5px; 131 left: 20%; 132 position: relative; 133 width: 200px; 134 font-size: 20px; 135 text-align : center; 136 background: lightgrey; 137 border-radius: 5px; 138 box-shadow: 0px 1px 1px; 139 140 } 141 .but-container{ 142 width: 100%; 143 height: 50px; 144 position: relative; 145 top:20px; 146 } 147 .content{ 148 width: 100%; 149 height:480px; 150 position: relative; 151 top:20px; 152 font-size: 18px; 153 } 154 .word{ 155 display: block; 156 float: left; 157 position: relative; 158 width:20%; 159 text-align : center; 160 } 161 .explain{ 162 display: block; 163 float: left; 164 position: relative; 165 width: 80%; 166 text-align : center; 167 } 168 .title{ 169 font-size: 20px; 170 } 171 .content>.explain{ 172 left:10%; 173 text-align: left; 174 } 175 </style> 176 </head> 177 <body> 178 <div class="container"> 179 180 <div class="top-container"> 181 <div class="headtitle">专业单词测试</div> 182 <div class="ebuttom" onclick="changewordlist()">产生随机单词</div> 183 </div> 184 <!--<h2 class="word">单词</h2>--> 185 <!--<div class="explain">解释</div>--> 186 <div class="but-container"> 187 <div class="title word">单词</div> 188 <div class="title explain">解释</div> 189 </div> 190 191 </div> 192 193 <script> 194 let wordsBase = new Array(); 195 let count=20; 196 let wordlistf=new Array(); 197 /** 198 * 用于将基础的字符串转换为需要的Object数组 199 * @ps 由于我们是通过\n来分解字符串,而字符串最后有一个/n,所以length得减一。 200 * a [string] 201 * return Array 202 */ 203 function trans( a ) 204 { 205 206 let wordesArray = a.split( "\n" ); 207 208 for( let i = 0; i < wordesArray.length - 1; i++ ) 209 { 210 let wordArray = wordesArray[ i ].split( "\t" ); 211 let word = wordArray[ 0 ]; 212 let explain = wordArray[ 1 ]; 213 let wordBase = { 214 word: word, 215 explain: explain 216 }; 217 wordsBase.push( wordBase ); 218 } 219 return wordsBase; 220 } 221 wordsBase=trans(a); 222 223 /** 224 * 用于从min到max中输出count个不重复随机数字。 225 * @param count number 226 * @param min number 227 * @param max number 228 */ 229 function norepeatRandom( count, min, max ) 230 { 231 let resultArray = []; 232 // resultArray.length = 20; 233 let markArray = []; 234 // markArray.length = 100; 235 // console.log(1,resultArray.length,markArray.length); 236 //确保可以取到max 237 let range = max - min + 1; 238 for( let i = 0; i < count; ) 239 { 240 let randomnumber = (range * Math.random() + min) >> 0; 241 if( !markArray[ randomnumber ] ) 242 { 243 resultArray[ i ] = randomnumber; 244 markArray[ randomnumber ] = 1; 245 i++; 246 } 247 } 248 return resultArray; 249 } 250 251 /** 252 * 用于从Object数组wordlist中获取数组randomlist中数字指向的Object元素,并且组成新的数组,返回。 253 * @param wordlist Array 254 * @param randomlist Array 255 */ 256 function randomArray( wordlist,randomlist ) 257 { 258 let wordlist20=[]; 259 for(let i=0;i<randomlist.length;i++){ 260 wordlist20[i]=wordlist[randomlist[i]]; 261 wordlist20[i]=wordlist[randomlist[i]]; 262 } 263 return wordlist20; 264 } 265 266 267 /** 268 * 点击产生新的随机单词list 269 * @param e 获取单击事件 270 */ 271 function changewordlist( e ) 272 { 273 e = event || window.event; 274 wordlistf=randomArray( wordsBase,norepeatRandom( 20, 0, 99 ) ); 275 let count=20; 276 let $contentinit=$(".container>.content"); 277 if($contentinit.length){ 278 console.log($contentinit); 279 $contentinit.remove(); 280 } 281 282 283 $(".container>.but-container").after( "<div class=\"content\"></div>\n"); 284 for(let i=0;i<count;i++){ 285 let wordf=wordlistf[i].word; 286 let explainf=wordlistf[i].explain; 287 let $content=$(".container>.content"); 288 $content.append( "<div class=\"word\">"+wordf+"</div>\n" + 289 "\t\t\t<div class=\"explain\">"+explainf+"</div>"); 290 // $content.append( "<div class=\"word\">单词</div>\n" + 291 // "\t\t\t<div class=\"explain\">解释</div>"); 292 } 293 } 294 </script> 295 </body> 296 </html>
四、题后思考:
那么问题来了。在之前问题思考中,有一个JS的index()方法,来实现这个算法。那么到底哪个算法会节省系统资源呢?
之后我想写一个相关的测试函数,运算时间方面,完全可以在测试函数的开头与结尾都获取一个时间戳,通过两者的差值就可以算出这个算法的运行时间。那么内存、运算量等相信也可以通过一些方法解决。但是如何提高这个测试函数的通用性,也就是如何让这个测试函数可以测试多个类型的算法呢,毕竟不同的算法有着不同的参数,有时候还需要调用个函数等等。所以这个思考分为两个部分,一个是这个算法的性能测试,一个是测试函数的拓展。