法鲁洗牌数组


31

法鲁洗牌是经常使用的魔术到“洗牌”甲板的技术。要执行Faro随机播放,您首先将卡座切成相等的两半,然后将这两个半插入。例如

[1 2 3 4 5 6 7 8]

法鲁洗牌是

[1 5 2 6 3 7 4 8]

可以重复多次。有趣的是,如果重复此次数足够多,您将总是回到原始数组。例如:

[1 2 3 4 5 6 7 8]
[1 5 2 6 3 7 4 8]
[1 3 5 7 2 4 6 8]
[1 2 3 4 5 6 7 8]

请注意,1停留在底部,8停留在顶部。这使它成为外部改组。这是一个重要的区别。

挑战

给定一个整数数组A和一个数字N,在N Faro随机播放后输出该数组。A可能包含重复的元素或否定的元素,但它将始终具有偶数个元素。您可以假设该数组不会为空。您还可以假设N将是一个非负整数,尽管它可以是0。您可以采用任何合理的方式获取这些输入。以字节为单位的最短答案为胜!

测试IO:

#N, A,                                              Output
1,  [1, 2, 3, 4, 5, 6, 7, 8]                        [1, 5, 2, 6, 3, 7, 4, 8]
2,  [1, 2, 3, 4, 5, 6, 7, 8]                        [1, 3, 5, 7, 2, 4, 6, 8]
7,  [-23, -37, 52, 0, -6, -7, -8, 89]               [-23, -6, -37, -7, 52, -8, 0, 89]
0,  [4, 8, 15, 16, 23, 42]                          [4, 8, 15, 16, 23, 42]
11, [10, 11, 8, 15, 13, 13, 19, 3, 7, 3, 15, 19]    [10, 19, 11, 3, 8, 7, 15, 3, 13, 15, 13, 19]

并且,一个庞大的测试案例:

23, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100]

应该输出:

[1, 30, 59, 88, 18, 47, 76, 6, 35, 64, 93, 23, 52, 81, 11, 40, 69, 98, 28, 57, 86, 16, 45, 74, 4, 33, 62, 91, 21, 50, 79, 9, 38, 67, 96, 26, 55, 84, 14, 43, 72, 2, 31, 60, 89, 19, 48, 77, 7, 36, 65, 94, 24, 53, 82, 12, 41, 70, 99, 29, 58, 87, 17, 46, 75, 5, 34, 63, 92, 22, 51, 80, 10, 39, 68, 97, 27, 56, 85, 15, 44, 73, 3, 32, 61, 90, 20, 49, 78, 8, 37, 66, 95, 25, 54, 83, 13, 42, 71, 100]  

数组可以包含零个元素吗?
Leaky Nun

@LeakyNun我们会说不,您不必处理零个元素。
DJMcMayhem



1
如果重复有限次,则任何有限集的置换都将返回到它开始的地方;这对Faro洗牌并不特殊。
格雷格·马丁

Answers:



19

vim,62 59 54

qrma50%mb:norm@q<cr>ggqOjdd'apjma'b@q<esc>0"qDJ<C-a>D@"i@r<esc>xxdd@"

哇。这可能是我为PPCG编写的最骇人听闻的东西,也就是说。

输入在第一行中取为N,后跟数组元素,每行分别。

qr         first, we're going to record the contents of the @r macro. this is
             the macro which does the faro-shuffle operation.
  ma       set the mark 'a at the beginning of the file
  50%      move to the 50% point of the file (i.e. halfway down)
  mb       set another mark here
  :norm@q  evaluate the recursive macro @q. we'll get to what that does later,
             but the interesting part here is that it's :norm@q instead of @q.
             this is because a recursive macro terminates at the end of the
             file, which means when @q terminates, @r would also abort, which
             would make calling it with a count impossible. running @q under
             :norm prevents this.
  gg       move back to the top of the file for the next iteration
q          end recording
O          now we're inserting contents of the @q macro, the recursive part
             we can't record it directly because it's destructive
  j        move to line directly below mark 'b (which was just set before @q)
  dd       delete this line and bring it...
  'ap      up after mark 'a (which starts on line 1, bringing the N/2th line
             directly below line 1, aka line 2)
  jma      replace mark 'a one line below this so that the next time we call
             'ap, the line from the second half is interleaved with the lines
             from the first half
  'b       jump back to mark 'b (remember, 'b is the last line of the first
             half of the file, originally reached via 50%)
  @q       call ourselves, causing the macro to run until hitting EOF
0"qD       delete this into register "q
J          delete the empty line that remains
<C-a>      here's another interesting bit: we want to run @r N times. but 0@r
             means "go to column 0, and then run @r once." so we have to
             increment the input number...
D@"        and then *that* many times...
  i@r        insert @r...
xx         ... and finally, delete two characters, which is the extra @r from
             the increment
dd         delete the sequence of @rs into the "" register...
@"         and run it!

在编写此答案时,我实际上可能发现了几个vim错误:

  • 在其他宏内(当手动设置其文本时,不能使用来设置文本q)或在:*maps中无法录制宏。

  • :let @a='<C-v><cr>'<cr>i<C-r>a 不管是什么不可思议的原因,都会输出两条换行符,而不是一条。

我可能会在以后进一步调查。

感谢Green Eggs博士和Ham DJ提供3个字节!


4
这是美丽而恐怖的。我可能没有足够的耐心在vim中执行此操作。:P此外,您还可以通过做起飞2个字节"rck,而不是vgg"rc,你可以通过做起飞另外5 dw@"i@r<esc>而不是AA@R<C-v><esc><esc>0D@"
DJMcMayhem

@DrGreenEg​​gsandHamDJ无法执行第一个操作,因为它也捕获了尾随的换行符,但是第二个优化有效。谢谢!
门把手

7

Python 2,59个字节

def f(n,L):exec"l=len(L)/2;L=(L+L[1:]*~-l)[::l];"*n;print L

一种不同的方法,比其他Python答案稍长。仅适用于正偶数个元素。

例如对于1, [1,2,3,4,5,6,7,8],获取数组并附加len(L)/2-1自身的副本减去第一个元素,例如

[1,2,3,4,5,6,7,8,2,3,4,5,6,7,8,2,3,4,5,6,7,8,2,3,4,5,6,7,8]

然后考虑所有len(L)/2要素。

[1,2,3,4,5,6,7,8,2,3,4,5,6,7,8,2,3,4,5,6,7,8,2,3,4,5,6,7,8]
 ^       ^       ^       ^       ^       ^       ^       ^

6

Python,68 57字节

f=lambda n,x:n and f(n-1,sum(zip(x,x[len(x)/2:]),()))or x

感谢@ Sp3000打高尔夫球11个字节!

Ideone上进行测试


6

Haskell,62个字节

0!a=a
n!a|s<-length a=(n-1)![a!!mod(div(s*i+i)2)s|i<-[0..s-1]]

s = 2· t为列表的大小。新列表的第i个元素是通过获取enter image description here旧列表的第n个元素(零索引,模s)获得的

证明:如果i = 2· k是偶数,则

                                         enter image description here

如果i = 2· k + 1为奇数,则

                        enter image description here

因此,用于索引的值是0,t,1,t + 1、2,t + 2…


5

J-12个字节

副词(!)在左侧采用随机播放的数量,在右侧采用随机播放的数组。

/:#/:@$0,#^:

J解析器有编写隐式副词的规则,但是它们的优先级很低:如果要使用一系列动词作为左参数,则可以省略其他必要的括号。所以以上实际上是(/:#/:@$0,#)^:,它将左侧的随机播放次数作为副词,然后变为单调函数,将数组的右侧随机播放。

就是说,我们如下洗牌。#是数组的长度,0,#两个元素列表也是:0,后跟非零值。然后将其#/:@$复制到与输入数组一样长的列表中,并采用其排序向量

列表的排序向量是有关如何对列表进行排序的信息:最小元素的(从0开始)invdex,后跟最小的索引,依此类推。例如,的排序向量0 1 0 1 ...将为0 2 4 ... 1 3 5 ...

如果J现在要对这种排序向量进行排序,它将对其进行Faro洗牌;但这将是微不足道的,因为我们会0 1 2 3 ...回来的。因此,我们使用yadic/:对输入数组进行排序,就好像它是一样 0 2 4 ... 1 3 5 ...,这会对其进行 Faro随机排序。

下面是示例用法。在tryj.tk上尝试一下!

   1 (/:#/:@$0,#^:) 1 2 3 4 5 6 7 8
1 5 2 6 3 7 4 8

   f =: /:#/:@$0,#^:

   2  f  1 2 3 4 5 6 7 8
1 3 5 7 2 4 6 8

   7  f  _23 _37 52 0 _6 _7 _8 89   NB. "negative 1" is spelled _1
_23 _6 _37 _7 52 _8 0 89

   1  f  0 0 0 0 1 1 1              NB. odd-length lists
0 1 0 1 0 1 0

5

Pyth- 8 7个字节

@issacg节省了1个字节

usCc2GE

在这里在线尝试


2
嗯...如果Pyth击败果冻,果冻答案中肯定有问题。
Leaky Nun

2
交换输入顺序并删除Q以保存一个字节。如果Jelly击败Pyth,Pyth的回答肯定有问题。:)
isaacg

@isaacg darn,我之前可能曾尝试过发誓。为什么行得通?难道不应该将它u与None 的默认值挂钩并定点吗?
Maltysen

@Maltysen是的,我认为它只是在我尝试过的一个测试用例上起作用。对于那个很抱歉。
isaacg

@LeakyNun感谢@Dennis@issacg,Pyth和Jelly现在相等(7个字节)。; D
Kevin Cruijssen

3

果冻9 7个字节

2个字节感谢丹尼斯!

œs2ZFð¡

在线尝试!

说明

œs2ZFð¡  Main dyadic chain. Arguments: x,y
      ¡  Repeat the following y time:
œs2          Split into two.
   Z         Transpose.
    F        Flatten.

先前的9字节版本:

œs2ZF
Ç⁴¡

在线尝试!


2

JavaScript(ES6),61 51字节

(n,a)=>[...a].map((e,i)=>a[(i<<n)%~-a.length||i]=e)

修改输入数组,并返回原始数组的副本。如果这是不可接受的,&&a则可以添加后缀以返回修改后的数组。n由于JavaScript整数运算的限制,仅适用于较小的值。基于@Lynn公式的61 60字节递归版本,可与nlarge一起使用:

f=(n,a,l=a.length)=>n?f(n-1,a.map((_,i)=>a[(i*-~l>>1)%l])):a

2

MATL,11个字节

w:"tn2/e!1e

感谢@Dennis的更正

在线尝试!

说明

w         % Take the two inputs N and A. Swap them
:         % Generate [1 2 ... N]
"         % Repeat N times
  tn2/    %   Duplicate A. Number of elements divided by 2
  e       %   Reshape to that number of rows
  !       %   Transpose
  1e      %   Reshape to one row
          % End (implicit)
          % Display (implicit)

为什么有w必要?
大卫(David

@David那是更正。如果没有它,则对于N = 0,不会进入循环,也不会进行第二次输入
Luis Mendo

啊,真烦人!
大卫(David

2

J,22 19 17字节

3字节感谢@Gareth

感谢@algorithmshark 2个字节。

-:@#({.,@,.}.)]^:

用法

>> f =: -:@#({.,@,.}.)]^:
>> 2 f 1 2 3 4 5 6 7 8
<< 1 3 5 7 2 4 6 8

>>STDIN和<<STDOUT 在哪里。

以前的22字节版本:

({~[:,/@|:@i.2,-:@#)^:

用法

>> f =: ({~[:,/@|:@i.2,-:@#)^:
>> 2 f 1 2 3 4 5 6 7 8
<< 1 3 5 7 2 4 6 8

>>STDIN和<<STDOUT 在哪里。


由于J的解析规则,您可以将外部paren删除2个字符。
algorithmhark

替代使用转置的索引{~2,@|:@i.@,-:@#^:18个字节
2016年

使用另一种替代17个字节[:,@|:]]\~_2%~#^:
英里

@milesI相信,@|:@$~2,-:@#^:可以工作15个字节
Jonah

1

Mathematica 44字节

@miles节省了4个字节。

Riffle@@TakeDrop[#,Length@#/2]&~Nest~##&

Riffle @@ TakeDrop[#, Length@#/2] &~Nest~## &[list, nShuffles]将列表分为两个相等的子列表,并对其进行随机排序Riffle


 Riffle @@ TakeDrop[#, Length@#/2] &~Nest~## &[Range@8, 1]

{1,5,2,6,3,7,4,8}


Riffle @@ TakeDrop[#, Length@#/2] &~Nest~## &[Range@100, 23]

{1,30,59,88,18,47,76,6,35,64,93,23,52,81,11,40,69,98,28,57,86,16,45,74,4 ,33,62,91,21,50,79,9,38,67,96,26,55,84,14,43,72,2,31,60,89,19,48,77,7,36 ,65、94、24、53、82、12、41、70、99、29、58、87、17、46、75、5、34、63、92、22、51、80、10、39、68 ,97,27,56,85,15,44,73,3,32,61,90,20,49,78,8,37,66,95,25,54,83,13,42,71,100 }


使用,TakeDrop我们可以找到一个使用40个字节的解决方案,Riffle@@TakeDrop[#,Length@#/2]&~Nest~##&同时还将##要解析的序列作为的附加参数Nest
2016年

@miles。很好用TakeDrop。并且最好使用##插入序列。
DavidC

1

APL, 23 21个字符

({⊃,/⍵(↑,¨↓)⍨2÷⍨⍴⍵}⍣N)A

在没有假设的情况下(感谢丹尼斯)且缩短了1个字符:

({{∊,⌿2(2÷⍨≢⍵)⍴⍵}⍣⎕)⎕

在线试用。


1

Java,109个字节

int[]f(int[]a,int n){for(int x,q=a.length,d[];0<n--;a=d){d=new int[q];for(x=0;x<q;x++)d[(2*x+2*x/q)%q]=a[x];}return a;}

说明:有一种模式可对元素进行随机混洗时如何移动:

令x为原始索引

令y为新索引

令L为数组的长度

  • y是x的两倍
  • 如果x大于或等于L的一半,则递增y
  • 将y保持在数组范围内

或作为代码: y=(2*x+x/(L/2))%L

假设索引从0开始。这是进一步解释的代码:

int[] faroShuffle( int[] array, int numberOfShuffles ) {
    //repeat the faro shuffle n times
    for( int index, length=array.length, destination[]; 0<numberOfShuffles--; array=destination ) {
        //new array to copy over the elements
        destination=new int[length];
        //copy the elements into the new array
        for( index=0; index<length; index++ )
            destination[(2*index+2*index/length)%length]=array[index];
        //at the end of each loop, copy the reference to the new array and use it going forward
    }
    return array;
}  

有关测试用例,请参见ideone


我知道已经一年多了,但是您可以打高尔夫:void f(int[]a,int n){for(int x,q=a.length,d[];0<n--;a=d)for(d=new int[q],x=0;x<q;)d[(2*x+2*x/q)%q]=a[x++];}107字节 -您当前的答案是119 btw,而不是109,所以-12字节)。由于您修改了输入数组,因此无需返回它,因此您可以将其更改为void以减少字节数。哦,如果你转换为一个Java 8拉姆达与讨好你可以使它更短:a->n->{for(int x,q=a.length,d[];0<n--;a=d){d=new int[q];for(x=0;x<q;x++)d[(2*x+2*x/q)%q]=a[x];}}96个字节
凯文Cruijssen

1

朱莉娅,45 42字节

a\n=n>0?reshape(a,endof(a)÷2,2)'[:]\~-n:a

在线尝试!

怎么运行的

我们(重新)定义\此任务的二进制运算符。设a为数组,n为非负整数。

如果 n为正,我们将对数组进行洗牌。这可以通过将其重塑为长度(a)÷2行和两列的矩阵来实现。'转置结果矩阵,创建两行,然后使用展平结果[:]。由于Julia按列优先顺序存储矩阵,因此这会交错两行。

之后,我们\以改组后的an-1~-n)作为参数进行递归调用,从而执行其他改组。一旦ñ达到0,我们返回的当前值一个


0

Pyke,7个字节

VDlec,s

在这里尝试!

V       - Repeat N times:
 D      -  a,b = a (2nd arg first time round)
  le    -  b = len(b)//2
    c   -  a = chunk(a,b)
     ,  -  a = zip(*a)
      s -  a = sum(a, [])

0

实际上是15个字节

`;l½≈@│t)HZ♂i`n

在线尝试!

说明:

`;l½≈@│t)HZ♂i`n
`            `n  do the following n times:
 ;l½≈              push half the length of the array
     @             swap
      │            duplicate entire stack
       t)H         last L//2 elements, first L//2 elements
          Z♂i      zip, flatten each element

0

Prolog,116个字节

a([],[[],[]]).
a([H,I|T],[[H|U],[I|V]]):-a(T,[U,V]).
f(X,0,X).
f(X,N,Y):-N>0,M is N-1,f(X,M,Z),a(Z,[A,B]),append(A,B,Y).

用法

?- f([1,2,3,4,5,6,7,8],2,X).
X = [1, 5, 2, 6, 3, 7, 4, 8] ;
false.


0

PHP,98字节

function($a,$n){while($n--)for($z=count($a)/2;$z;)array_splice($a,$z--,0,array_pop($a));return$a;}

在线尝试

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.