血夜之末 阅读(31) 评论(0)

随机产生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()方法,来实现这个算法。那么到底哪个算法会节省系统资源呢?

  之后我想写一个相关的测试函数,运算时间方面,完全可以在测试函数的开头与结尾都获取一个时间戳,通过两者的差值就可以算出这个算法的运行时间。那么内存、运算量等相信也可以通过一些方法解决。但是如何提高这个测试函数的通用性,也就是如何让这个测试函数可以测试多个类型的算法呢,毕竟不同的算法有着不同的参数,有时候还需要调用个函数等等。所以这个思考分为两个部分,一个是这个算法的性能测试,一个是测试函数的拓展。