let rangeArray = (start, end) => Array(end - start + 1).fill(0).map((v, i) => i + start)
rangeArray(0,10) // return [0,1,2,3,4,5,6,7,8,9,10]
由于map不能对数组中未赋值的元素进行遍历,所以可以通过 ES6 的新方法 fill 对数组进行填充,把数组中的所有数转为0(转成什么都无所谓),然后通过 map 方法将数组中所有0都转成对应的数字。
ES5 没有 fill 方法也可以通过 Array.apply(null, {length: end - start + 1}).map((v, i) => i + start) 搞定。说起来比第一种方法速度可能更快。
random:
let randomArray = (start, end) => {
let range = rangeArray(start, end)
, random = []
while (range.length) {
let i = Math.random() * range.length | 0
random.push(range[i])
range.splice(i, 1)
}
return random
}
// test
let random = randomArray(1, 50)
console.log(random.length === 50)
console.log(Math.min.apply(Math, random) === 1)
console.log(Math.max.apply(Math, random) === 50)
console.log(random.sort((a, b) => a - b).every((v, i, a) => v === a[i - 1] || 0 + 1))
具体原理就是:生成一个 range 数组,然后随机 range 数组的长度,得到下标 i,取出 range 中下标为 i 的元素放入新数组 random 中, 删除 range 数组这个元素,接着循环,直到 range 数组被删完。
最近在看「算法」,所以厚着脸皮分析下时间复杂度吧,不对的地方欢迎指出:生成一个 range 数组,2n 次循环,循环 range 数组 n 次,所以加起来就是 3n 次,所需时间为线性级别的,时间复杂度为 O(n),所以看起来还是挺快的。
作为对比,分析一种以前经常用到的方法:
let randomArray = (start, end) => {
let o = {}
, length = end - start + 1
, random = []
while (random.length < length) {
let i = (Math.random() * length + 1) | 0
if (o[i]) continue
else {
o[i] = true
random.push(i)
}
}
return random
}
// test
let random = randomArray(1, 50)
console.log(random.length === 50)
console.log(Math.min.apply(Math, random) === 1)
console.log(Math.max.apply(Math, random) === 50)
console.log(random.sort((a, b) => a - b).every((v, i, a) => v === a[i - 1] || 0 + 1))
从上面代码可以看到在最好的情况下(不会出现 random 结果重复的情况),所需的时间复杂度为 O(n),最坏的情况下(每次都重复的话...循环到无数次),这样就只能算期望了,数学不好就不瞎算了。
let a = [], b = []
console.time('push')
for (let i = 0; i < 1e5; i++) {
a.push(i)
}
console.timeEnd('push') // ==> 3ms
console.time('splice')
for (let i = 0; i < 1e5; i++) {
b.splice(i, 1, i)
}
console.timeEnd('splice') // ==> 21ms
从上面可以看出splice花费的时间远远超过push 。
写着写着就好像与标题相差了万八千里.... 不过具体写了什么就没所谓了,权当记录。
======= 2015-11-4 更新 ======
let randomArray1 = (start, end) => {
let range = rangeArray(start, end)
, random = []
, N = range.length
while (N--) {
let i = Math.random() * (N + 1) | 0
random.push(range[i])
range[i] = range[N]
//range.splice(i, 1)
}
return random
}
避免使用 splice 方法,算法没什么变化,实现写法改了一点点,速度大大提升,测试结果如下:
console.time('random1')
let random1 = randomArray1(1, 1e5)
console.timeEnd('random1')
console.time('random2')
let random2 = randomArray2(1, 1e5)
console.timeEnd('random2')
random1: 12ms
random2: 79ms
创建数组除了字面量和
new Array()
外,还可以通过Array(n)
创建,n 为数组的长度。Array(n)
生成了长度为 n 的空数组,注意,和数组中元素赋值为 undefined 是有区别的;chrome 中查看空数组为[undefined * n]
,而赋值为 undefined 的数组为[undefined, undefined, ..... , undefined]
。range:
由于
map
不能对数组中未赋值的元素进行遍历,所以可以通过 ES6 的新方法fill
对数组进行填充,把数组中的所有数转为0(转成什么都无所谓),然后通过map
方法将数组中所有0都转成对应的数字。ES5 没有
fill
方法也可以通过Array.apply(null, {length: end - start + 1}).map((v, i) => i + start)
搞定。说起来比第一种方法速度可能更快。random:
具体原理就是:生成一个 range 数组,然后随机 range 数组的长度,得到下标 i,取出 range 中下标为 i 的元素放入新数组 random 中, 删除 range 数组这个元素,接着循环,直到 range 数组被删完。
最近在看「算法」,所以厚着脸皮分析下
时间复杂度
吧,不对的地方欢迎指出:生成一个 range 数组,2n 次循环,循环 range 数组 n 次,所以加起来就是 3n 次,所需时间为线性级别的,时间复杂度为 O(n),所以看起来还是挺快的。作为对比,分析一种以前经常用到的方法:
从上面代码可以看到在最好的情况下(不会出现 random 结果重复的情况),所需的时间复杂度为 O(n),最坏的情况下(每次都重复的话...循环到无数次),这样就只能算期望了,数学不好就不瞎算了。
自己对上面的分析之后认为在输入数特别大的情况下,前一种方法会把后一种方法碾压成渣,然而实际情况是反被轰成了渣滓,原因是忽略了splice方法,splice 是对数组的元素进行移动操作,会耗费了大量时间。
从上面可以看出splice花费的时间远远超过push 。
写着写着就好像与标题相差了万八千里.... 不过具体写了什么就没所谓了,权当记录。
======= 2015-11-4 更新 ======
避免使用 splice 方法,算法没什么变化,实现写法改了一点点,速度大大提升,测试结果如下:
可以看到在我的电脑下,对1万条数据的处理速度提升了接近6倍。和之前的分析结果还算是相符的。