Фаро переміщує масив


31

Faro перетасувати є метод часто використовується магами «Перемішати» колода. Щоб виконати перемикання Faro, спочатку розріжте колоду на 2 рівні половинки, потім ви переплетете дві половини. Наприклад

[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 Фаро перетасовується. А може містити повторювані або негативні елементи, але завжди матиме парну кількість елементів. Ви можете припустити, що масив не буде порожнім. Ви також можете припустити, що 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
Будь-яка перестановка скінченного набору, якщо повториться достатньо разів, закінчиться там, де вона почалася; це не особливо для Фаро змішується.
Грег Мартін

Відповіді:



19

вим, 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 Green Eggs та Ham DJ за 3 байти!


4
Це красиво і жахливо. Я, мабуть, не вистачаю терпіння, щоб зробити це in vim. :PТакож ви можете зняти 2 байти, виконуючи "rckзамість цього vgg"rc, а можете зняти ще 5, зробивши dw@"i@r<esc>замістьAA@R<C-v><esc><esc>0D@"
DJMcMayhem

@DrGreenEggsandHamDJ Не можу зробити це першим, тому що він також захоплює нову лінію, але ця друга оптимізація працює. Спасибі!
Дверна ручка

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

Пітон, 68 57 байт

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

Дякуємо @ Sp3000 за те, що виграли 11 байт!

Перевірте це на Ideone .


6

Хаскелл, 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 - розмір списку. Я -й елемент нового списку виходить взяттям введіть тут опис зображення-го елемента старого списку, нульовий індекс, по модулю s .

Доведення: якщо i = 2 · k парне, то

                                         введіть тут опис зображення

і якщо i = 2 · k + 1 непарне, то

                        введіть тут опис зображення

Таким чином, значення, використані для індексації, є 0, t , 1, t + 1, 2, t + 2,…


5

J - 12 байт

Прислівник (!), Що приймає кількість перетасовок зліва та масив, щоб перетасувати справа.

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

J-аналізатор має правила написання негласних прислівників , але вони мають дуже низький пріоритет: якщо ви хочете використовувати поїзд дієслів як лівий аргумент, ви можете опустити інакше необхідний набір дужок. Таким чином, вищезазначене насправді коротке (/:#/:@$0,#)^:, що сприймає кількість перетасовок зліва як прислівник, а потім стає монадичною функцією, яка приймає масив переміщуватися праворуч.

Однак, ми перемішуємось так. #- це довжина масиву, так 0,#це список двох елементів: 0, за яким слід щось не нульове. Потім #/:@$реплікує це до списку до вхідного масиву і приймає його сортуючий вектор .

Вектором сортування списку є інформація про те, як сортувати список: адекдекс найменшого елемента, заснований на 0, з наступним індексом наступного-найменшого тощо. Наприклад, 0 1 0 1 ...таким буде вектор сортування 0 2 4 ... 1 3 5 ....

Якби J зараз сортував цей сортовий вектор, Фаро змістив би його; але це було б банально, оскільки ми повернемось 0 1 2 3 ...назад. Таким чином, ми використовуємо dyadic/: для сортування вхідного масиву так, як би він 0 2 4 ... 1 3 5 ... Фаро перетасовує його.

Приклад використання нижче. Спробуйте самі на 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 байт

збережено 1 байт завдяки @issacg

usCc2GE

Спробуйте його онлайн тут .


2
Хм ... повинно бути щось не так у відповіді Джелі, якщо Піт б'є Джелі.
Leaky Nun

2
Поміняйте порядок введення та видаліть, Qщоб зберегти байт. У відповіді Pyth повинно бути щось не так, якщо Jelly б'є Pyth. :)
isaacg

@isaacg Блін, я міг би присягнути, що я пробував це раніше. Чому це працює? Чи не повинен цей гачок за замовчуванням для " uNone" і робити фіксовану точку?
Мальтісен

@Maltysen Ти маєш рацію, я думаю, що це сталося лише над одним тестовим випадком, який я намагався. Вибач за це.
isaacg

@LeakyNun Завдяки @Dennis та @issacg , Pyth та Jelly тепер рівні (7 байт). ; D
Кевін Круїссен


2

JavaScript (ES6), 61 51 байт

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

Змінює вхідний масив на місці та повертає копію вихідного масиву. Якщо це неприпустимо, &&aможна повернути суфікс для повернення модифікованого масиву. Працює лише для малих значень nчерез обмеження цілочисельної арифметики JavaScript. 61- байт-рекурсивна версія, яка працює з більшою n, заснованою на формулі @ Лінна:

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 Це було виправлення. Без нього для N = 0 цикл не вводиться і другий вхід не береться
Луїс Мендо

Ах, це дратує!
Девід

2

J, 22 19 17 байт

3 байти завдяки @Gareth .

2 байти завдяки @algorithmshark .

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

Використання

>> 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 ви можете скидати зовнішні паролі на 2 символи.
Алгоритм

Альтернативно, використовуючи транспонований індекс {~2,@|:@i.@,-:@#^:на 18 байт .
милі

Інший варіант , який використовує 17 байт також[:,@|:]]\~_2%~#^:
милі

@milesI вважаю, що ,@|:@$~2,-:@#^:працює на 15 байт
Йона

1

Математика 44 байти

З 4 байтами збережено завдяки @miles.

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.
миль

@miles. Дуже приємне використання TakeDrop. І краще використовувати ##для вставки послідовності.
DavidC

1

APL, 23 21 символ

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

Без припущення (спасибі Деннісу) і на 1 char коротше:

({{∊,⌿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
  • якщо х більший або дорівнює половині 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 байт). Оскільки ви змінюєте вхідний масив, повертати його не потрібно, тому ви можете змінити його на порожнечу, щоб зменшити байти. О, і якщо ви перетворите на 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];}}
лямбду

1

Юлія, 45 42 байти

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

Спробуйте в Інтернеті!

Як це працює

Ми (пере) визначаємо двійковий оператор \для цього завдання. Нехай a - масив, а n - негативне ціле число.

Якщо n позитивний, ми переміщуємо масив. Це досягається шляхом перестановки її в матрицю довжиною (a) ÷ 2 рядки та два стовпчики. 'транспонує отриману матрицю, створюючи два ряди, потім вирівнюючи результат за допомогою [:]. Оскільки Джулія зберігає матриці в порядку основного стовпця, це переплутує два ряди.

Після цього ми називаємо \рекурсивно аргументами переміщені a і n - 1 ( ~-n) в якості аргументів, тим самим виконуючи додаткові переміщення. Як тільки n досягає 0 , ми повертаємо поточне значення 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

Пролог, 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.


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.