@@ -1305,6 +1305,20 @@ def rotate!(cnt=1)
1305
1305
replace ary
1306
1306
end
1307
1307
1308
+ class SampleRandom
1309
+ def initialize ( rng )
1310
+ @rng = rng
1311
+ end
1312
+
1313
+ def rand ( size )
1314
+ random = Rubinius ::Type . coerce_to_collection_index @rng . rand ( size )
1315
+ raise RangeError , "random value must be >= 0" if random < 0
1316
+ raise RangeError , "random value must be less than Array size" unless random < size
1317
+
1318
+ random
1319
+ end
1320
+ end
1321
+
1308
1322
def sample ( count = undefined , options = undefined )
1309
1323
return at Kernel . rand ( size ) if undefined . equal? count
1310
1324
@@ -1326,29 +1340,80 @@ def sample(count=undefined, options=undefined)
1326
1340
end
1327
1341
1328
1342
rng = options [ :random ] if options
1329
- rng = Kernel unless rng and rng . respond_to? :rand
1330
-
1331
- unless count
1332
- random = Rubinius ::Type . coerce_to_collection_index rng . rand ( size )
1333
- raise RangeError , "random value must be >= 0" if random < 0
1334
- raise RangeError , "random value must be less than Array size" unless random < size
1335
-
1336
- return at random
1343
+ if rng and rng . respond_to? :rand
1344
+ rng = SampleRandom . new rng
1345
+ else
1346
+ rng = Kernel
1337
1347
end
1338
1348
1349
+ return at rng . rand ( size ) unless count
1350
+
1339
1351
count = size if count > size
1340
- result = Array . new self
1341
- tuple = Rubinius ::Mirror ::Array . reflect ( result ) . tuple
1342
1352
1343
- count . times do |i |
1344
- random = Rubinius ::Type . coerce_to_collection_index rng . rand ( size )
1345
- raise RangeError , "random value must be >= 0" if random < 0
1346
- raise RangeError , "random value must be less than Array size" unless random < size
1353
+ case count
1354
+ when 0
1355
+ return [ ]
1356
+ when 1
1357
+ return [ at ( rng . rand ( size ) ) ]
1358
+ when 2
1359
+ i = rng . rand ( size )
1360
+ j = rng . rand ( size )
1361
+ if i == j
1362
+ j = i == 0 ? i + 1 : i - 1
1363
+ end
1364
+ return [ at ( i ) , at ( j ) ]
1365
+ else
1366
+ if size / count > 3
1367
+ abandon = false
1368
+ spin = 0
1347
1369
1348
- tuple . swap i , random
1349
- end
1370
+ result = Array . new count
1371
+ i = 1
1372
+
1373
+ result [ 0 ] = rng . rand ( size )
1374
+ while i < count
1375
+ k = rng . rand ( size )
1376
+ j = 0
1377
+
1378
+ while j < i
1379
+ while k == result [ j ]
1380
+ spin += 1
1381
+ if spin > 100
1382
+ abandon = true
1383
+ break
1384
+ end
1385
+ k = rng . rand ( size )
1386
+ end
1387
+ break if abandon
1388
+
1389
+ j += 1
1390
+ end
1391
+
1392
+ break if abandon
1393
+
1394
+ result [ i ] = k
1395
+
1396
+ i += 1
1397
+ end
1398
+
1399
+ unless abandon
1400
+ i = 0
1401
+ while i < count
1402
+ result [ i ] = at result [ i ]
1403
+ i += 1
1404
+ end
1405
+
1406
+ return result
1407
+ end
1408
+ end
1409
+
1410
+ result = Array . new self
1411
+ tuple = Rubinius ::Mirror ::Array . reflect ( result ) . tuple
1350
1412
1351
- return count == size ? result : result [ 0 , count ]
1413
+ count . times { |i | tuple . swap i , rng . rand ( size ) }
1414
+
1415
+ return count == size ? result : result [ 0 , count ]
1416
+ end
1352
1417
end
1353
1418
1354
1419
def select! ( &block )
0 commit comments