Об’єднайте два відсортовані списки


14

Об’єднати сортування

У цьому виклику ви реалізуєте підпрограму злиття сортування злиття. Зокрема, ви повинні створити функцію, програму або дієслово чи подібне, яке займає два списки, кожен сортований у порядку зростання, і об'єднує їх у один список, відсортований у порядку збільшення. Вимоги:

- Ваш алгоритм повинен забирати асимптотично лінійну кількість часу в розмірі вводу. Будь ласка, припиніть давати рішення O (n ^ 2).

  • Ви не можете використовувати будь-які вбудовані функції, здатні сортувати список, чи об’єднувати список, чи щось подібне. На розсуд автора.
  • Код повинен мати можливість обробляти повторювані елементи.
  • Не турбуйтеся про порожні списки.

Приклади:

merge([1],[0,2,3,4])
[0,1,2,3,4]

merge([1,5,10,17,19],[2,5,9,11,13,20])
[1, 2, 5, 5, 9, 10, 11, 13, 17, 19, 20]

Це , тому може виграти найкоротший код!


Чи потрібно обробляти повторювані елементи у списку чи лише між двома списками?
Кіт Рендалл

Скажімо, обидва. Ідея полягає в тому, що ви повинні мати можливість використовувати це для сортування злиття.
isaacg

Це кошерно клобувати вхідні масиви?
skibrianski

3
Я не впевнений, як інтерпретувати алгоритм повинен забирати асимптотично лінійну кількість часу . Алгоритми не займають часу, їх реалізація. Час виконання моєї відповіді на Гольфскрипт O (страшно) з інтерпретатором Ruby, але Інтернет-тестер Golfscript поводиться набагато краще і насправді може бути лінійним (однак жоден реальний спосіб розповісти без вихідного коду). Моя суть: b=a;b=b.lengthможе дублювати весь масив a(і приводити до часу O (n ^ 2), якщо він виконується для кожного елемента) або дублювати лише посилання на масив (O (n) час). Який з них рахується?
Денніс

1
Я думаю, що у таких випадках, просто зробіть все можливе, щоб це зрозуміти, але якщо ви, чесно кажучи, не можете сказати, ви можете припустити, що все добре працює, як і друга альтернатива, яку ви згадали. Можна припустити, що перекладач працює добре, якщо у вашій мові немає стандартного перекладача.
isaacg

Відповіді:


8

Ребму ( 35 32 символи)

u[iG^aNXa[rvA]apGtkFaM?fA]apGscA

Тест

>> rebmu/args [u[iG^aNXa[rvA]apGtkFaM?fA]apGscA] [[1 5 10 17 19] [2 5 9 11 13 20]] 
== [1 2 5 5 9 10 11 13 17 19 20]

>> rebmu/args [u[iG^aNXa[rvA]apGtkFaM?fA]apGscA] [[2 5 9 11 13 20] [1 5 10 17 19]] 
== [1 2 5 5 9 10 11 13 17 19 20]

Про

Rebmu - це діалект Ребола, який дозволяє "збивати" звичайний код для ситуацій, які вимагають стислості. Невмілий, код працює приблизно так:

u [                     ; until
    i g^ a nx a [       ; if greater? args next args
       rv a             ; reverse args
    ]                   ; (we want the block containing the next value first)

    ap g tk f a         ; append output take first args
    m? f a              ; empty? first args
]                       ; (first block is now empty)

ap g sc a               ; append output second args
                        ; (add the remainder of the second)

Я вважаю, що це задовольняє вимогу O (n), оскільки блок поки не максимум циклічний стільки разів, скільки довжина вводу (і reverseєдиний перемикає порядок контейнера вхідних блоків, а не самих блоків). Використанняtake , можливо, є свободою, але все-таки є незначним ефектом ефективності.

Ребол ( 83 75 символів)

Просто по-різному: в Реболі шляхи - це коротший вираз, ніж firstабо second. a- це блок введення, що містить два блоки:

until[if a/2/1 < a/1/1[reverse a]append o:[]take a/1 tail? a/1]append o a/2

5

Рішення ОП:

Haskell 49 44 40

k@(p:r)%l@(q:s)|p>=q=q:k%s|0<1=l%k
a%_=a

Пітон 131 105 101 99 93

Дякуємо @Evpok:

f=lambda u,v:v and(v[-1]<u[-1]and f(v,u)or[b.append(a)for a,b in[(v.pop(),f(u,v))]]and b)or u

1
Ви можете написати a%b=a++bпісля відповідного основного шаблону, щоб обробити порожні списки, які позбавлять пару символів.
швейцарський

чи не вдалося вирішити Haskell, якщо в першому списку не вистачає вмісту?
Джон Дворак

Якщо ви подивитесь на першу функцію, вона рекурсивно викликає функцію зі скороченим списком як другий аргумент, а подовжений список - як перший аргумент, інакше поміняє аргументи. Тому перший аргумент ніколи не стає коротшим. Оскільки за ОП він не починається порожнім, він ніколи не порожній.
isaacg

4

Пітон (79)

from itertools import*
def m(*a):
 while any(a):yield min(compress(a,a)).pop(0)

Python (95, якщо нам не дозволяють повернути генератор)

from itertools import*
def m(*a):
 r=[]
 while any(a):r+=[min(compress(a,a)).pop(0)]
 return r

Itertools - це рішення всіх світових проблем.

Бонус: ці два працюють за довільною кількістю списків, і НЕ турбуйтеся про порожні списки (як, наприклад, вони із задоволенням візьмуть 2 порожні списки та повернуть порожній список, або візьмуть 1 порожній та 1 не порожній список, і вони повернуть не порожній. Ще одна додана функція двох неприбуткових: вони також запустять без аргументів і просто повернуть порожній список.)

Безголівки:

from itertools import *  # Import all items from itertools
def m(*a):               # Define the function m, that takes any number of arguments, 
                         #  and stores those arguments in list a
    r=[]                 # Create an empty list r                         
    while any(a):        # While any element in a returns True as value:
        b=compress(a,a)  # Remove any element from a that isn't True (empty lists)
                         #  The example in the official documentation is this one:
                         #  compress('ABCDEF', [1,0,1,0,1,1]) --> A C E F
        c=min(b)         # Sort the lists by first value, and take the first one of these.
        d=c.pop(0)       # Take the first element from c
        r.append(d)      # Append this first element to r
    return r             # Gives back r

У своїх рішеннях без генератора використовуйте r+=[...]замість r.append(...)(економить 4 символи кожного разу)
hlt

Я не маю на увазі жодних злочинів цим, але якщо ваша відповідь містить код мовою, яка є просто іншою мовою з модифікаціями, зробленими спеціально для гри в гольф, я збираюсь оскаржити це. Соромно, справжні відповіді пітона хороші.
підземниймонорельс

Якщо ви розділите їх на різні посади, я підтримаю пітон.
підземниймонорельс

4
@undergroundmonorail Ви спростуєте всі відповіді GolfScript?
Євпок

1
@Evpok Тепер, коли ви згадуєте про це, можливо, також киньте його на мета і подивіться, що вони там мають сказати.
ɐɔıʇǝɥʇuʎs

3

С - 75

Це працює на NULLзавершених масивах int *, хоча це було б однаково добре для покажчиків на інші типи, замінюючи відповідну функцію порівняння для **b < **a(наприклад, strcmp(*b, *a) < 0).

void m(int**a,int**b,int**c){while(*a||*b)*c++=!*a||*b&&**b<**a?*b++:*a++;}

Безголівки:

void merge(int **a, int **b, int **c)
{
    while(*a || *b)
        *c++ = !*a || *b && **b < **a
            ? *b++
            : *a++;
}

3

Гольфскрипт, 29 27 30 29 26 байт

~{.0=@.0=@<{}{\}if(@@.}do;~]p

або

~{.0=@.0=@>{\}*(@@.}do;~]p

Як це працює

Команда

golfscript merge.gs <<< '[2 3] [1 4]'

буде оброблено наступним чином:

~            # Interpret the input string.
             #
             # STACK: [2 3] [1 4]
{            #
    .@=0.@=0 # Duplicate the two topmost arrays of the stack and extract their first 
             # elements. This reverses the original order of the first copy.
             #
             # STACK: [1 4] [2 3] 2 1
             #
    >        # Check if the respective first elements of the arrays are ordered.
             #
             # STACK: [1 4] [2 3] 1
             #
    {\}*     # If they are not, swap the arrays. This brings the array with the smallest
             # element to the top of the stack.
             #
             # STACK: [2 3] [1 4]
             #
    (@@      # Shift the first element of the array on top of the stack and rotate it
             # behind the arrays.
             #
             # STACK: 1 [2 3] [4]
             #
    .        # Duplicate the topmost array.
             #
             # STACK: 1 [2 3] [4] [4]
             #
}do          # Repeat this process if the array is non-empty.
             #
             # STACK: 1 [2 3] [4] -> 1 2 [4] [3] -> 1 2 3 [4] []
             #
;~           # Delete the empty array from the stack and dump the non-empty array.
             #
             # STACK: 1 2 3 4
             #
]p           # Combine all elements on the stack into a single array, the to a string and
             # print.

Вихід:

[1 2 3 4]

Чи робить дублювання масивів у стеку O (n ^ 2)?
швейцарський

@swish: Я не вчений-комп'ютер, але я б сказав, що це залежить від реалізації. Якщо перекладач насправді копіює цілі масиви, я думаю, це так і є.
Денніс

Попередня версія була O (n ^ 2) для дуже схожих масивів (наприклад, [1 1 1 ... 2]і [1 1 1 ... 3]), оскільки порівняння масивів (а не їх перших елементів) було б дуже повільним у цьому випадку.
Денніс

Єдині операції з масивом, які відбуваються в новій версії, - це дублювання, заміна та обертання на стеку. Оскільки дублюються масиви використовуються лише для вилучення одиночних елементів і тестування масивів на відсутність порожнечі (обидві деструктивні операції в Golfscript), вищезазначений код може бути запущений у O (n) час (шляхом дублювання, заміни та обертання посилань на масиви). Фактична ефективність залежить від перекладача.
Денніс

2

J - 42 33

Змінена версія звідси + коментар @algorithmshark

k=:(m}.),~0{]
m=:k~`k@.(>&{.) ::,

kпередує заголовку правого масиву до об'єднаних хвостів обох масивів. k~те саме, але з перекинутими масивами. (>&{.)порівнює голови. Код видасть помилку, якщо один з масивів порожній, у такому випадку ми повертаємо лише їх об'єднання ,.


Я припускаю, що оскільки /:~ a,bзаборонена відповідь (разом із [:/:~,), ви знімаєте найкоротшу відповідь, яка не включає /:, правда?
Дейн

Я зазначу, що в запитанні сказано: "Не хвилюйтесь про порожні списки".
Дейн

@Dane Тест на порожнечу, необхідний для припинення рекурсії.
swish

m=:k~`k@.(>&{.)`,@.(0=*&#)економить 2 чару.
алгоритм

Насправді ви можете звести всю справу до 33 знаків: k=:(m}.),~0{]і m=:k~`k@.(>&{.) ::,. Ми використовуємо, 0{щоб викинути помилку, коли список порожній, а потім зафіксувати цю помилку та вийти із ,.
алгоритм

2

JavaScript (ES6), 69 79 байт

f=(a,b,c=[])=>(x=a[0]<b[0]?a:b).length?f(a,b,c.concat(x.shift())):c.concat(a,b)

Як це працює

f = (a, b, c = []) =>          // `f' is a function that takes arguments `a', `b' and `c' -
                               // `c' defaults to `[]' - which returns the following
                               // expression:
                               //
 (x = a[0] < b[0] ? a : b)     // Store the array among `a' and `b' with the smaller first 
                               // element in `x'.
                               //
 .length ?                     // If it's non-empty,
                               //
  f(a, b, c.concat(x.shift())) // append the first element of array `x' to array `c' and run
                               // `f' again;
                               //
  : c.concat(a,b)              // otherwise, append the arrays `a' and `b' to `c'.
                               //
)

Порівнювати масиви з <оператором не f([123, 456, 789], [1, 2, 3, 4, 5]) => [1, 123, 2, 3, 4, 456, 5, 789]
вірно,

@nderscore: Правильно. Як би це не працювало, оскільки порівняння цілих масивів може бути не O (n). Це ж здається справедливим і для тесту на порожнечу, який повинен перетворити весь масив у рядок.
Денніс

Так, я не впевнений, що таке велике перетворення для масиву-> рядок.
nderscore

1
Об'єднання масиву з, []а потім перетворення його в рядок вимагає часу O (n). Зробити це один раз для всіх n елементів масиву потрібно O (n ^ 2) час.
Денніс

Має сенс. Зрозумів.
nderscore

2

Пітон (63) (69) (71)

def m(a,b):
 if a[0]>b[0]:a,b=b,a
 return[a.pop(0)]+(m(a,b)if a else b)

Я написав це, перш ніж побачити коментарі ОП щодо часу виконання інших відповідей, тож це ще одне рішення, яке є O (n) в алгоритмі, але не реалізація.


Які алгоритми мають витяги з фронту масивів як O (1)? За якими алгоритмами порівняння списків приймає O (1)? Крім того, ви можете додатково
пограти в

@isaacg Shoot, я забув про повтори, можливо, роблячи порівняння списку O (n). Отже, я взяв цю оптимізацію для ще 6 символів. Ви можете витягнути з нього та додати його на передню частину в O (1) у пов'язаному списку. Я не бачу, як можна зробити ... і ... або ... грати добре, повертаючи значення.
xnor

Гаразд, зараз я бачу, як це зробити ... і ... або ..., але це не зберігає символів через необхідні паролі. return[a.pop(0)]+(a and m(a,b)or b)
xnor

@isaacg: Щоб витягнути передню частину масиву в O (1), просто збільште покажчик масиву таким чином, щоб він вказував на другий елемент і звільнив пам'ять, споживану першим елементом.
Wrzlprmft

@Wrzlprmft Я не міг змусити трюк масиву працювати, оскільки обидва елементи масиву оцінюються незалежно від булевого значення, яке видає помилку, коли a - це порожній список. Чи є короткий спосіб зробити "ледачий масив"?
xnor

2

Haskell, 35 байт

a#b@(c:d)|a<[c]=b#a|0<1=c:a#d
a#_=a

Haskell, 30 байт (неконкурентоспроможний)

Ця неконкурентна версія гарантує лише лінійну тривалість виконання, якщо вона має aі bнепересічні елементи; інакше він все ще працює правильно, але може використовувати квадратичний час.

a#b|a<b=b#a|c:d<-b=c:a#d
a#_=a

2

PHP 91 98 91 байт

редагування №1: Порожній $bвимагає додаткової умови в фігурних дужках (+7).
редагувати №2: другорядне гольф
редагувати №3: додана друга версія

досить прямо вперед. Найприємніша частина - потрійний всередині array_shift
(який не вдається, якщо спробувати його без фігур)

function m($a,$b){for($c=[];$a|$b;)$c[]=array_shift(${$a&(!$b|$a[0]<$b[0])?a:b});return$c;}

або

function m($a,$b){for($c=[];$a|$b;)$c[]=array_shift(${$a?!$b|$a[0]<$b[0]?a:b:b});return$c;}

неозорий

function m($a,$b)
{
    $c=[];
    while($a||$b)
    {
        $c[] = array_shift(${
            $a&&(!$b||$a[0]<$b[0])
                ?a
                :b
        });
#       echo '<br>', outA($a), ' / ', outA($b) , ' -> ', outA($c);
    }
    return $c;
}

тест

$cases = array (
    [1],[0,2,3,4], [0,1,2,3,4],
    [1,5,10,17,19],[2,5,9,11,13,20], [1, 2, 5, 5, 9, 10, 11, 13, 17, 19, 20],
    [1,2,3],[], [1,2,3],
    [],[4,5,6], [4,5,6],
);
function outA($a) { return '['. implode(',',$a). ']'; }
echo '<table border=1><tr><th>A</th><th>B</th><th>expected</th><th>actual result</th></tr>';
while ($cases)
{
    $a = array_shift($cases);
    $b = array_shift($cases);
#   echo '<hr>', outA($a), ' / ', outA($b) , ' -> ', outA($c);
    $expect = array_shift($cases);
    $result=m($a,$b);
    echo '<tr><td>',outA($a),'</td><td>',outA($b),'</td><td>', outA($expect), '</td><td>', outA($result),'</td></tr>';
}
echo '</table>';

Я не міг зрозуміти, чому ви робите це не просто $a&(!$b|$a[0]<$b[0])?$a:$bзамість${$a&(!$b|$a[0]<$b[0])?a:b}
Йорг Гюльсерманн

1
@ JörgHülsermann array_shiftПараметр використовується посиланням. Він повинен бути змінною; вираз не буде працювати.
Тит

1

Ідіть, 124 ч

func m(a,b[]int)(r[]int){for len(a)>0{if len(b)==0||a[0]>b[0]{a,b=b,a}else{r=append(r,a[0]);a=a[1:]}};return append(r,b...)}

1

JavaScript - 133

function m(a,b){c=[];for(i=j=0;i<a.length&j<b.length;)c.push(a[i]<b[j]?a[i++]:b[j++]);return c.concat(a.slice(i)).concat(b.slice(j))}

Той самий підхід, що й у ОП.


1

perl, 87 chars / perl 5,14, 78 + 1 = 79 chars

Ця реалізація клобує посилання на вхідний масив. Крім цього, це досить прямо: в обох масивах є щось, змістіть нижній з двох. Потім поверніть об'єднаний біт, з'єднаний з будь-якими залишилися бітами (залишиться лише один з @ $ x або @ $ y). Прямий вгору5, 87 символів:

sub M{($x,$y,@o)=@_;push@o,$$x[0]>$$y[0]?shift@$y:shift@$x while@$x&&@$y;@o,@$x,@$y}

Використовуючи perl 5.14.0 та його новомодний зсув масиву: 78 символів + 1 знак покарання = 79 знаків:

sub M{($x,$y,@o)=@_;push@o,shift($$x[0]>$$y[0]?$y:$x)while@$x&&@$y;@o,@$x,@$y}

*замість &&збереже байт. І навіть більше, якщоsub M{map{shift(!@$x+@$y*($$y[0]<$$x[0])?$y:$x)}map@$_,($x,$y)=@_}
user2846289

@VadimR, вау. хороша робота. Вперед та опублікуйте, що вам подобається - я ніколи б не подумав зробити трюк з подвійною картою, а не натискати на масив.
skibrianski

1

Ява: 144

Це досить просто. Функція, яка займає два масиви і повертає один, об'єднану версію, гольф і без обгортки компіляції:

int[]m(int[]a,int[]b){int A=a.length,B=b.length,i,j;int[]c=new int[A+B];for(i=j=0;i+j<A+B;c[i+j]=j==B||i<A&&a[i]<b[j]?a[i++]:b[j++]);return c;}

Ungolfed (з можливістю компіляції та запуску):

class M{
    public static void main(String[]args){
        int[]a=new int[args[0].split(",").length];
        int i=0;
        for(String arg:args[0].split(","))
            a[i++]=Integer.valueOf(arg);
        int[]b=new int[args[1].split(",").length];
        int j=0;
        for(String arg:args[1].split(","))
            b[j++]=Integer.valueOf(arg);
        int[]c=(new M()).m(a,b);
        for(int d:c)
            System.out.printf(" %d",d);
        System.out.println();
    }
    int[]m(int[]a,int[]b){
        int A=a.length,B=b.length,i,j;
        int[]c=new int[A+B];
        for(i=j=0;i+j<A+B;c[i+j]=j==B||i<A&&a[i]<b[j]?a[i++]:b[j++]);
        return c;
    }
}

Приклади виконання:

$ javac M.java
$ java M 10,11,12 0,1,2,20,30
 0 1 2 10 11 12 20 30
$ java M 10,11,12,25,26 0,1,2,20,30
 0 1 2 10 11 12 20 25 26 30

Будь-які поради щодо скорочення були б вдячні.


1

Скала, 97 байт

Рекурсивний розчин з O (n). Для скорочення коду іноді виконується операція шляхом перемикання двох взаємозамінних параметрів, тобто f (a, b) викликів f (b, a).

type L=List[Int];def f(a:L,b:L):L=if(a==Nil)b else if(a(0)<=b(0))a(0)::f(a.drop(1),b) else f(b,a)

Безголівки:

type L=List[Int]

def f(a:L, b:L) : L =
  if (a == Nil)
    b 
  else 
    if (a(0) <= b(0))
      a(0) :: f(a.drop(1), b) 
    else
      f(b,a)

Виняток, якщо а не порожній, але b порожній
Дан Осипов

1

APL (32)

{⍺⍵∊⍨⊂⍬:⍺,⍵⋄g[⍋g←⊃¨⍺⍵],⊃∇/1↓¨⍺⍵}

Пояснення:

{⍺⍵∊⍨⊂⍬                               if one or both of the arrays are empty
        :⍺,⍵                           then return the concatenation of the arrays
             ⋄g[⍋g←⊃¨⍺⍵]              otherwise return the sorted first elements of both arrays
                          ,⊃∇/        followed by the result of running the function with
                               1↓¨⍺⍵}  both arrays minus their first element

1

LISP, 117 байт

Алгоритм закінчується n + 1ітераціями, де nдовжина найкоротшого списку введення.

(defun o(a b)(let((c(car a))(d(car b)))(if(null a)b(if(null b)a(if(< c d)(cons c(o(cdr a)b))(cons d(o a(cdr b))))))))


0

Пітон - 69 байт

def m(A,B):
    C=[]
    while A and B:C+=[[A,B][A>B].pop(0)]
    return C+A+B

Якщо порядок введення та виведення зменшувався, це може бути скорочено до 61 байта :

def m(A,B):
    C=[]
    while A+B:C+=[[A,B][A<B].pop(0)]
    return C

І далі до 45 байт, якщо генератори дозволені:

def m(A,B):
    while A+B:yield[A,B][A<B].pop(0)

Це точно не O (n). .pop (0) і + = - це обидва операції O (n), які ви виконуєте O (n) разів.
isaacg

Я навіть досі не знав, що списки не реалізовані як списки в Python, і навіть тоді вони pop(0)можуть бути реалізовані в O (1) і +=принаймні можуть бути реалізовані краще, ніж O (n) (див. Посилання). До речі, ваше рішення використовує +=(тобто, appendі extend) так само часто, як і моє. У будь-якому випадку, все, що стосується питання про реалізацію (наскільки я знаю), тому в (вигаданій) реалізації Python, де списки реалізуються як списки, моя функція - O (n). Нарешті, ваше запитання вимагало, щоб алгоритм був O (n), а мій -.
Wrzlprmft

Actually, append and extend are implemented differently in python than += is. += creates a new list, while .append and .extend modify an existing one.
isaacg

0

Perl 6: 53 characters

sub M(\a,\b){{shift a[0]>b[0]??b!!a}...{a^b},a[],b[]}

Shift from whichever of a or b has the smaller value, until a XOR b (a^b) is true. Then return whatever is left, flattening ([]) the arrays into the list (a[],b[]).

Assuming shifting from the start of an array is O(n), the worst case is two comparisons and one shift per element, so the algorithm is O(n).


0

JavaScript (ES5) 90 86 90 bytes

function f(a,b){for(o=[];(x=a[0]<b[0]?a:b).length;)o.push(x.shift());return o.concat(a,b)}

edit: (90 - >86) Moved the ternary into the for loop condition. Idea stolen from Dennis.

edit: (86 -> 90) Removed Array to String cast, as it breaks the O(n) requirement.


0

Mathematica, 137 135

m[a_,b_]:=(l=a;Do[Do[If[b[[f]]<=l[[s]],(l=Insert[l,b[[f]],s];Break[]),If[s==Length@l,l=l~Append~b[[f]]]],{s,Length@l}],{f,Length@b}];l)

Input:

m[{2,2,4,6,7,11},{1,2,3,3,3,3,7}]

Output:

{1, 2, 2, 2, 3, 3, 3, 3, 4, 6, 7, 7, 11}

Ungolfed:

mergeList[a_, b_] := (
    list = a;
    Do[
        Do[(
            If[
                b[[f]] <= list[[s]],
                (list = Insert[list, b[[f]], s]; Break[]),
                If[
                    s == Length@list,
                    list = list~Append~b[[f]]
                ]
        ]),
        {s, Length@list}
    ],
    {f, Length@b}
    ];
    list
)

Could probably do better.


m[a:{x___,y_},b:{___,z_}]:=If[y<z,b~m~a,{x}~m~b~Join~{y}];{}~m~b_=b;
alephalpha

0

R, 80

Same solution as in Scala and other languages. I am not so sure about x[-1] is O(1).

f=function(a,b)if(length(a)){if(a[1]<=b[1])c(a[1],f(a[-1],b))else f(b,a)}else b

0

Mathematica, 104 bytes

Reap[{m,n}=Length/@{##};i=k=1;Do[If[k>n||TrueQ[#[[i]]<#2[[k]]],Sow@#[[i++]],Sow@#2[[k++]]],n+m]][[2,1]]&

Anonymous function, stores the length of the two input lists in the variables m and n, then each iteration of the Do loop Sows an element of one the lists incrementing the counter for that list (i for the first, k for the second) by one. If one of the counters exceeds the length of the list, the If statement will always Sow the element from the other list. After n+m operations, all the elements have been taken care of. Reap or rather part [[2,1]] of its output is a list of elements in the order they have been Sown.

I'm not sure of the internals (is accessing a part of a list a O(1) operation or not), but timings looked quite linear on my machine with respect to input list length.

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