产生随机排列


30

挑战说明

序列的“排列”是一种排列,其中没有元素出现在其原始位置。例如,ECABD是的排列ABCDE,但CBEDA不是:

ABCDE
 | |   <- B and D are in their orignal positions
CBEDA

给定一个序列,生成它的随机排列。

笔记

  • 您可以将字符串作为输入或元素(整数,字符,对象...)的数组/列表

  • 无需返回新对象,而是可以通过交换其元素来修改现有对象

  • 每次错序产生的可能性均等

  • 您可以假设序列中有多个元素,并且没有一个以上元素出现



3
@VoteToClose:哈哈,完全捣毁
shooqie

我对这一切了解不多,但这与定点定理有什么关系……根据这种定理,事物总是以自己的位置或类似的东西结束……?我打赌我错了,但是有人请纠正我:)
Farhan Anam

是否可以保证这些元素是唯一的,或者它们可以包含重复项?
Carcigenicate

1
@Carcigenicate:就在描述中;您可能会假设没有重复
shooqie '16

Answers:


12

CJam,14个字节

q:X{mr_X.=:|}g

在线尝试!

不断改组输入,直到出现混乱为止。

说明

q:X   e# Read input and store it in X.
{     e# While the condition at the end of the loop is truthy...
  mr  e#   Shuffle the string.
  _X  e#   Duplicate it and push the input.
  .=  e#   Element-wise equality check.
  :|  e#   Reduce OR over the list, gives something truthy if any character
      e#   remained in its original position.
}g

1
我希望OP已指定解决方案必须保证它们始终能够完成。
约翰·德沃夏克

4
@JanDvorak好吧,此操作未完成的概率为0。但是,您是对的,因为需要确定的运行时间才能使挑战变得更加有趣。
马丁·恩德

概率实际上是0吗?随机播放操作并不完美,它实际上如何工作?我认为这可能是OP要求的一个很好的近似值,但是我怀疑每个排列错乱的可能性是否相同(可能取决于随机排序操作可能使用的PRNG的某些种子值)。
没人

3
@没人,我怀疑您可以使用任何算法从PRNG中获得完全一致的结果。但是,假设改组本身是统一的(Java文档对此进行了保证,“所有排列均以近似相等的可能性发生”。)基于拒绝的解决方案也将产生统一的排列,因为每个排列都是一个排列,每个排列排列具有相同的概率。
马丁·恩德

1
@没人数学书呆子在这里。成功或失败的条件在统计上称为伯努利试验。这意味着需要k次尝试才能获得首次成功的概率为(1- p)^(k-1)* p,其中p是成功重排的概率。很容易看出,随着k的增大,需要进行k次试验的可能性越来越小。因此,我们说该算法以概率1(“几乎可以肯定”)停止,但并非永远不会停止。
仆人

9

果冻,6个字节

Ẋ=³S$¿

在线尝试!

说明

Ẋ    ¿    Shuffle the given list while this is nonzero for it:
    $       A two-step process:
 =³           Element-wise equality of it and L (the original list)...
   S          Sum the ones in this binary array.

乔纳森·艾伦(Jonathan Allan)保存了一个字节。


5
因此,您提前获得了Winter Bash帽子吗?:-)
路易斯·门多

2
是时候画一张漂亮的新图片了,Ẋ=³S$¿节省了一个字节。
乔纳森·艾伦

2
never,我从来不知道$。谢谢!
林恩

它是6个字符,但超过6个字节。Ẋ=³S$¿字节长度为:312112。因此总共10个字节。
mxfh

6

Python,85个字节

修改传递给它的列表(由meta和问题允许)。

from random import*
def D(l):
 o=l[:]
 while any(x==y for x,y in zip(o,l)):shuffle(l)

在这里在线尝试!


1
如果您指定Python 2,我认为您可以替换def D(l):l=input(),然后在以下几行中保存缩进空间(因此您拥有一个程序而不是一个函数)。不过没有投票!
mathmandan '16

@mathmandan是个好主意,但是如果它是一个完整的程序,那么我需要再次打印出它,这会花费更多的字节。
FlipTack

1
既然你这么说,那好吧。我想我对规范似乎是在说,您不必打印或返回结果-从[用户输入]中获取列表并重新排列列表就足够了。但是将“现有”理解为“在运行任何代码之前已存在”是合理的,在这种情况下,我同意您的观点。(也许对此已有公认的共识。):)
mathmandan '16

5

ES6(JavaScript), 71,69字节

输入和输出是数组,应该与任何元素类型(字符串,数字等)一起使用,只要它们可以与“ ==”进行比较即可。

打高尔夫球

F=s=>(r=[...s]).sort(_=>Math.random()-.5).some((e,i)=>s[i]==e)?F(s):r

测试

F=s=>(r=[...s]).sort(_=>Math.random()-.5).some((e,i)=>s[i]==e)?F(s):r

F(['A','B','C','D'])
Array [ "D", "C", "A", "B" ]

F(['A','B','C','D'])
Array [ "D", "A", "B", "C" ]

F(['A','B','C','D'])
Array [ "C", "D", "B", "A" ]

F(['A','B','C','D'])
Array [ "D", "C", "B", "A" ]

F(['A','B','C','D'])
Array [ "C", "D", "B", "A" ]

互动片段

F=s=>(r=[...s]).sort(_=>Math.random()-.5).some((e,i)=>s[i]==e)?F(s):r

function G() {
    console.log(F(T.value.split``).join``); 
}
<input id=T value="ABCDEF"><button id=G onclick="G()">GENERATE</button>


5

Perl 6、33字节

{first (*Zne$_).all,.pick(*)xx *}

一个以整数或字符组成的列表作为输入并返回一个新列表的lambda。

如果必须支持任意值列表,则必须ne替换为!eqv(+2字节)。

在线尝试。

说明:

  • { }:定义一个lambda。
  • .pick(*):生成输入列表的随机混洗。
  • .pick(*) xx *:创建此类混洗的惰性无限序列。
  • (* Zne $_).all:一个lambda,使用(负字符串相等)运算符压缩两个列表(其参数*和外部lambda的参数$_ne,产生一个布尔值列表,然后创建一个all结点以将它们折叠为单个布尔值状态。
  • first PREDICATE, SEQUENCE:从满足“失序”测试的无限排列序列中选取第一个元素。

4

Brachylog19 18 15 13字节

@~.:?z:#da;?&

在线尝试!

说明

@~.                Output is a shuffle of the input
  .:?z             Zip the output with the input
      :#da         All couples of integers of the zip must be different
          ;      Or
           ?&      Call recursively this predicate with the same input

3

Perl 6、45字节

{(@^a,{[.pick(*)]}...{none @a Zeqv@$_})[*-1]}
{(@^a,{[.pick(*)]}...{!sum @a Zeqv@$_})[*-1]}

试试吧

输入是任何东西的数组。

展开:

{
  (

    @^a,          # declare parameter, and seed sequence generator

    {             # lambda with implicit parameter 「$_」
      [           # store into an array
        .pick(*)  # shuffle 「$_」
      ]
    }

    ...           # keep generating the sequence until

    {
      none        # none
      @a          # of the outer blocks input
      Z[eqv]      # is zip equivalent
      @$_         # with the current value being tested
    }

  )[ * - 1 ]      # return the last value
}

3

MATL,7个字节

这是我的Octave帖子的翻译(与此处的其他一些提交内容相似)。我昨天发布了我的第一条MATL帖子(CNR破解),所以我认为这不是最佳选择,但这是我到目前为止所取得的最好成绩。

老实说,我不确定t那里是否需要它,但这是我可以使用它的唯一方法。使用它可以比较用户输入(G)与随机排列进行比较。我想我可以比较没有它的两个,但是...?

无论如何,这里是这样:

`Z@tG=a

`          % Loop
 Z@        % Random permutation of input
   t       % Duplicating the stack
    G      % Paste from clipboard G (user input)
     =     % Comparing the random permutation with the input (retrieved from clipboard)
      a    % any(input == random permutation)
           % Implicit end and display

在线尝试!


有什么改善吗?我真的需要t在那里还是可以摆脱它?尝试在MATL高尔夫很有趣... :)
Stewie Griffin

:-)我看不出如何摆脱它t(或同等的G东西),您需要在堆栈中保留某些内容以进行下一次迭代或最终结果
Luis Mendo

3

实际上,13个字节

;;WX╚│♀=ΣWX)X

在线尝试!

说明:

;;WX╚│♀=ΣWX)X
;;             make two copies of input
  WX╚│♀=ΣW     while top of stack is truthy:
   X             discard top of stack
    ╚            shuffle array
     │           duplicate entire stack
      ♀=         compare corresponding elements in shuffled and original for equality
        Σ        sum (truthy if any elements are in the same position, else falsey)
          X)X  discard everything but the derangement

2

八度,56 55字节

x=input('');while any(x==(y=x(randperm(nnz(x)))));end,y

input('')因为这不是函数,所以我们必须使用。另外,由于我可以选择将输入作为字符串,所以可以使用技巧nnz(x)==numel(x)

说明:

x=input('')            % Self-explanatory
while any(x==y)        % Loop until x==y has only 0s (i.e. no elements are equal)
y=x(randperm(nnz(x)))  % Continue to shuffle the indices and assign x(indices) to y
end                    % End loop
y                      % Display y

感谢Luis注意到输入可以是字符串,因此我可以使用nnz而不是numel保存两个字节。


自我注意:下次阅读整个问题:)谢谢!
Stewie Griffin

1
这一直在我身上发生:-)
路易斯·门多

2

MATL,13个字节

这是@LuisMendo和我的共同努力。与这里的许多其他答案相反,此答案是确定性的,因为它不会对随机排列进行采样,直到发生排列失调,而是生成所有排列并随机选择一个。

Y@tG-!Af1ZrY)

在线尝试!

说明

Y@tG-!Af1ZrY)
Y@             generate all permutatoins
  t            create a duplicate
   G-!A        find the (logical) indices of all valid derangements (where no character of the string is in the same position as the original string)
       f       convert logical to linear indices
        1Zr    choose one of those indices randomly
           Y)  get the derangement (from the ones we generated earlier) at this index

2

Pyth- 10 9个字节

当任何字符等于输入中其索引处的字符时,这会继续对输入进行改组。

.WsqVHQ.S

在这里在线尝试

.W           Iterate while
 s           Sum, this is works as any() on a boolean list
  qV         Vectorized equality
   H         The lambda variable for the check step
   Q         The input
 .S          Shuffle
  (Z)        Lambda variable, implicit
 (Q)         Start .W with input, implicit

能否请您解释一下。我想写一个pyth答案。我对此不太了解。
Gurupad Mamadapur

@GurupadMamadapur当然,也会很高兴。
Maltysen

1
@GurupadMamadapur添加了。我们有一个教程。它已经过时了,但是会教您一些基础知识。如果您需要有关pyth的任何帮助,请随时在聊天中ping我。
Maltysen

2

Mathematica,57个字节

#/.x_:>RandomChoice@Select[Permutations@x,FreeQ[#-x,0]&]&

未命名函数,将任何内容的列表作为输入并输出列表。在生成#输入的所有排列之后x,我们仅保留那些#-x元素方面的差异集不包含0; 然后我们从该集合中进行(均匀)随机选择。


1
真好!稍长一点,#/.x_:>NestWhile[RandomSample[#,Length@#]&,#,Not@FreeQ[#-x,0]&]&显然在长弦练习中会更快
马丁

等等,您是在告诉我Mathematica中没有内置的错位?:o
shooqie

我对自己的内建系统有一半的期望:)
格雷格·马丁

0

PHP,85字节

for($a=$b=str_split($argv[1]);array_diff_assoc($a,$b)!=$a;)shuffle($b);echo join($b);

将string参数复制到两个数组中,将它们中的一个进行混洗,直到它们之间的差(还比较元素的索引)等于另一个。用运行-r


0

R,59个字节

z=x=1:length(y<-scan(,""));while(any(x==z))z=sample(x);y[z]

将元素列表读取到STDIN,获取列表的长度,并开始从1到长度的采样范围,直到找到与顺序列表不共享任何位置的元素。然后打印该列表。


0

不可思议,32字节

f\@[/>#I zip#=[#0a\shuf#0]?f a?a

用法:

f\@[/>#I zip#=[#0a\shuf#0]?f a?a];f[1 2 3 4 5]

说明

更具可读性:

f\@[
  some #I zip #= [#0; a\ shuf #0]
    ? f a
    ? a
]

递归函数f。在f的输入列表和输入列表的随机版本之间进行逐元素比较。如果比较产生任何相等的值,则f在混洗的列表上调用。否则,我们仅返回经过改组的列表。



0

八度,54 53字节

@(a)((p=perms(a))(L=!any(p==a,2),:))(randi(sum(L)),:)

生成的所有排列 a并随机选择一个没有公共元素的行a

注意:偶然与@flawr MATL答案相同!


0

Clojure,94 90 79字节

#(let[s(shuffle %)](if(not(some(fn[[x y]](= x y))(map vector % s)))s(recur %)))

通过将条件内部的约简更改为-4字节 and并内联done?

通过将减少量转换为-11个字节 some

哇!击败PHP。

蛮力法。列表无效时随机播放。考虑到这是一种蛮力方法,它无法防止重复尝试,因此可以很快完成愚蠢的操作。它在不到一秒钟的时间内发现了1000个元素长的列表中的1000个变数。

取消高尔夫:

(defn dearang [ls]
  (let [s (shuffle ls)
        bad? (some (fn [[x y]] (= x y))
                (map vector ls s))]
    (if (not bad?) s (recur ls))))

0

Clojure,56个字节

#(let[s(shuffle %)](if((set(map = % s))true)(recur %)s))

请注意,字符串不能混洗,必须通过 seqvec

本来我尝试过#(first(remove(fn[s]((set(map = % s))true))(iterate shuffle %)))但是recur方法确实比iterate

魔术是(set(map = % s))返回一组false,一组true或一组true与false。这可以用作函数,如果包含true则答案为true,否则为falsy nil=很高兴接受两个输入参数,而无需将其包装任何东西。

((set [false]) true)
nil

也许有一种更短的方法来检查任何值是否为真?


0

APL,11个字节。

在正确的参数中包含字符串:

⍵[⍋(⍴⍵)?⍴⍵]

说明

ρ⍵ 获取正确参数的长度(或形状)。

?返回(⍴⍵)这些数字的随机数组。

返回它们的顺序,以确保没有重复。

⍵[..] 代表使用此索引的字符串的随机分类。


欢迎来到PPCG!我们要求所有条目都是有效的函数或完整程序,因此您的答案需要通过函数参数或输入法进行输入。
ETHproductions 2016年

我认为现在应该符合要求。它接受正确的参数或
雅各布·乌特利
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.