как сделать случайную выборку из списка или массива scala?

<p>я хочу сделать случайную выборку из списка или массива scala (не rdd), размер выборки может быть намного длиннее длины списка или массива, как я могу сделать это<strong> эффективно </strong>? поскольку размер выборки может быть очень большим, и выборка (в разных списках/массивах) должна выполняться большое количество раз.</p><p>я знаю, что для spark rdd мы можем использовать takesample (), есть ли эквивалент для списка/массива scala?</p><p>большое спасибо.</p>

<p>простая для понимания версия будет выглядеть так:</p><pre><code>import scala.util.random random.shuffle(list).take(n) random.shuffle(array.tolist).take(n) // seeded version val r = new random(seed) r.shuffle(...) </code></pre>

<p>для массивов:</p><pre><code>import scala.util.random import scala.reflect.classtag def takesample[t:classtag](a:array[t],n:int,seed:long) = { val rnd = new random(seed) array.fill(n)(a(rnd.nextint(a.size))) } </code></pre><p>создайте генератор случайных чисел (<code>rnd</code>) на основе вашего начального числа. затем заполните массив случайными числами от 0 до размера вашего массива.</p><p>последний шаг - применение каждого случайного значения к оператору индексации вашего входного массива. использование его в repl может выглядеть следующим образом:</p><pre><code>scala> val myarray = array(1,3,5,7,8,9,10) myarray: array[int] = array(1, 3, 5, 7, 8, 9, 10) scala> takesample(myarray,20,system.currenttimemillis) res0: scala.collection.mutable.arrayseq[int] = arrayseq(7, 8, 7, 3, 8, 3, 9, 1, 7, 10, 7, 10, 1, 1, 3, 1, 7, 1, 3, 7) </code></pre><p>для списков я просто преобразовал бы список в массив и использовал бы ту же функцию. я сомневаюсь, что вы все равно можете получить гораздо более эффективную работу со списками.</p><p><strong> важно отметить, что та же функция, использующая списки, будет занимать o (n ^ 2) времени, тогда как сначала преобразование списка в массивы займет o(n) время </strong></p>

<p>если вы хотите сделать выборку<em> без </em>/ замены - zip с случайными числами, сортируйте <code>o(n*log(n)</code>, отбросьте случайные числа, возьмите</p><pre><code>import scala.util.random val l = seq("a", "b", "c", "d", "e") val ran = l.map(x => (random.nextfloat(), x)) .sortby(\_.\_1) .map(\_.\_2) .take(3) </code></pre>

<p>используя классическую рекурсию.</p><pre><code>import scala.util.random def takesample[t](a: list[t], n: int): list[t] = { n match { case n: int if n <= 0 => list.empty[t] case n: int => a(random.nextint(a.size)) :: takesample(a, n - 1) } } </code></pre>

<p>используя для понимания, для данного массива <code>xs</code> следующим образом,</p><pre><code>for (i <- 1 to samplesize; r = (math.random * xs.size).toint) yield a(r) </code></pre><p>обратите внимание, что генератор случайных чисел здесь генерирует значения в единичном интервале, которые масштабируются так, чтобы варьироваться по размеру массива, и преобразуются в <code>int</code> для индексации по массиву.</p><p><strong>note</strong> для чисто функционального генератора случайных чисел рассмотрим, например, подход state monad из <a href="https://www.manning.com/books/functional-programming-in-scala">функциональное программирование в scala</a> , обсуждался <a href="https://stackoverflow.com/questions/31818787/pure-functional-random-number-generator-state-monad">здесь</a> .</p><p><strong>note</strong> рассмотрим также <a href="https://github.com/nicta/rng">nicta</a> , еще один чисто функциональный генератор случайных значений, его использование проиллюстрировано, например, <a href="https://stackoverflow.com/a/25655709/3189923">здесь</a> .</p>

<pre><code>package your.pkg import your.pkg.seqhelpers.sampleops import scala.collection.generic.canbuildfrom import scala.collection.mutable import scala.language.{higherkinds, implicitconversions} import scala.util.random trait seqhelpers { implicit def withsampleops[e, cc[\_] <: seq[\_]](cc: cc[e]): sampleops[e, cc] = sampleops(cc) } object seqhelpers extends seqhelpers { case class sampleops[e, cc[\_] <: seq[\_]](cc: cc[\_]) { private def recurse(n: int, builder: mutable.builder[e, cc[e]]): cc[e] = n match { case 0 => builder.result case \_ => val element = cc(random.nextint(cc.size)).asinstanceof[e] recurse(n - 1, builder += element) } def sample(n: int)(implicit cbf: canbuildfrom[cc[\_], e, cc[e]]): cc[e] = { require(n >= 0, "cannot take less than 0 samples") recurse(n, cbf.apply) } } } </code></pre><p>или: </p><ul> <li>mixin <code>seqhelpers</code>, например, со спецификацией scalatest</li> <li>включить <code>import your.pkg.seqhelpers.\_</code></li> </ul><p>тогда должно работать следующее:</p><pre><code>seq(1 to 100: \_*) sample 10 foreach { println } </code></pre><p>правки для удаления актерского состава приветствуются. </p><p>также, если есть способ создать пустой экземпляр коллекции для аккумулятора, не зная заранее конкретного типа, пожалуйста, прокомментируйте. тем не менее, строитель, вероятно, более эффективен.</p>

<p>не проверял на производительность, но следующий код - простой и элегантный способ сделать выборку, и я верю, что он может помочь многим, которые приходят сюда только для того, чтобы получить код выборки. просто измените «диапазон» в соответствии с размером вашего конечного образца. если псевдослучайности недостаточно для ваших нужд, вы можете использовать take (1) во внутреннем списке и увеличить диапазон.</p><p><code>random.shuffle((1 to 100).tolist.flatmap(x => (random.shuffle(yourlist))))</code></p>