Впорядкування основного списку на основі упорядкованого підмножини


19

Нещодавно у мене виникла проблема вирішення на роботі, де у мене було два списки: головний список та менший список, який містить підмножину елементів у головному списку, потенційно в іншому порядку. Мені потрібно було змінити основний список таким чином, щоб елементи в підмножині відображалися в тому самому порядку, не змінюючи порядок елементів, які не знайдені в списку, і зберігаючи елементи в тому самому місці, коли це можливо. Гаразд, це, мабуть, звучить заплутано, тому я зламаю це:

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

Ваше завдання - реалізувати цей алгоритм переупорядкування.

Приклади тестових випадків

Master: [1, 2, 3]
Subset: []
Result: [1, 2, 3]

Master: [9001, 42, 69, 1337, 420]
Subset: [69]
Result: [9001, 42, 69, 1337, 420]

Master: [9001, 42, 69, 1337, 420, 99, 255]
Subset: [69, 9001, 1337]
Result: [42, 69, 9001, 1337, 420, 99, 255]

Master: [1, 2, 3, 4, 5]
Subset: [2, 5]
Result: [1, 2, 3, 4, 5]

Master: [apple, banana, carrot, duck, elephant]
Subset: [duck, apple]
Result: [banana, carrot, duck, apple, elephant]

Master: [Alice, Betty, Carol, Debbie, Elaine, Felicia, Georgia, Helen, Ilene, Julia]
Subset: [Betty, Felicia, Carol, Julia]
Result: [Alice, Betty, Debbie, Elaine, Felicia, Carol, Georgia, Helen, Ilene, Julia]

Master: [snake, lizard, frog, werewolf, vulture, dog, human]
Subset: [snake, werewolf, lizard, human, dog]
Result: [snake, frog, werewolf, lizard, vulture, human, dog]

Master: [Pete, Rob, Jeff, Stan, Chris, Doug, Reggie, Paul, Alex]
Subset: [Jeff, Stan, Pete, Paul]
Result: [Rob, Jeff, Stan, Pete, Chris, Doug, Reggie, Paul, Alex]

Master: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
Subset: [8, 1, 2, 12, 11, 10]
Result: [3, 4, 5, 6, 7, 8, 1, 2, 9, 12, 11, 10]

Master: [lol, rofl, lmao, roflmao, lqtm, smh, jk, wat]
Subset: [wat, lmao, rofl]
Result: [lol, roflmao, lqtm, smh, jk, wat, lmao, rofl]

Правила

  • Стандартні лазівки, yadda yadda, зручні введення-виведення, бла-бла.
  • Незважаючи на те, що в прикладах використовуються числа та рядки, вам потрібно підтримувати лише один тип елемента, будь то цілі числа, рядки чи щось інше з чітко визначеною семантикою рівності, включаючи неоднорідні списки, якщо це зручно для вашої мови.
  • Ви можете припустити, що і основний, і список підмножин не містять дублікатів
  • Ви можете припустити, що всі елементи, знайдені у списку підмножин, знаходяться у головному списку
  • Будь-який список може бути порожнім
  • Ви повинні, як мінімум, підтримувати масиви довжиною до 100 елементів.
  • Переупорядкування може бути здійснено на місці або шляхом створення нового списку / масиву.

Щасливого гольфу!


1
Гарна, примхлива проблема.
Іона

Чи 8 1 3 4 5 6 7 2 9 12 11 10є правильним рішенням другого до останнього?
Високоповажний

@ Вен. Ні. Хоча це відповідає обмеженням збереження елементів підмножини в тому самому відносному порядку, я хотів переконатися, що існує лише одна правильна відповідь, тому попередній елемент, що не вийшов із замовлення, повинен бути переміщений на наступний пізніше товар поза замовленням
Beefster

Чому не важливо, що існує більше однієї правильної відповіді? Будь ласка, додайте обмеження до правил виклику, будь ласка.
Дост

Відповіді:


4

Сітківка 0,8,2 , 51 байт

+`(\b(\w+),(\w+)\b.*¶.*\b)\3,(.*\b\2\b)
$1$4,$3
1A`

Спробуйте в Інтернеті! Приймає введення як розділений комами список підрядів у першому рядку, а розділений комою головний список слів у другому рядку. Пояснення:

(\b(\w+),(\w+)\b.*¶.*\b)\3,(.*\b\2\b)

Знайдіть два суміжні підслови, де друге слово передує першому у головному списку.

$1$4,$3

Перемістіть друге слово, яке з’явиться після першого слова в головному списку.

+`

Повторюйте, поки жодні слова не з’являться з ладу.

1A`

Видаліть підслови.


4

JavaScript (ES6),  96 89 74  71 байт

Це почалося як об’ємний безлад і врешті-решт скоротилося до досить лаконічної та елегантної форми. Хочу подякувати методу .splice () за його плідну співпрацю з цим. ;)

Вводиться як " (master)(subset). Виводиться шляхом оновлення головного списку.

m=>s=>s.map(p=x=>m.splice(p,0,...m.splice(i=m.indexOf(x),p>i||!(p=i))))

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

Як?

ip

m.splice(p, 0, ...m.splice(i, condition))

1

  • i[елемент]
  • p

0

  • внутрішній .splice () нічого не видаляє і повертає порожній масив
  • в результаті зовнішній .splice () отримує невизначений як його 3-й аргумент, і нічого також не вставляється

Прокоментував

m => s =>                 // m[] = master list, s[] = subset list
  s.map(                  //
    p =                   // p = position in the master list of the last element from
                          //     the subset list (initialized to a non-numeric value)
    x =>                  // for each element x in the subset list:
    m.splice(             //   insert in the master list:
      p,                  //     at position p
      0,                  //     without removing any element
      ...m.splice(        //     remove from the master list and flatten:
        i = m.indexOf(x), //       i = position of x in the master list
        p > i             //       if p is greater than i, remove x from its current
                          //       position and insert it at position p
        || !(p = i)       //       otherwise, set p to i and don't remove/insert anything
      )                   //     end of inner splice()
    )                     //   end of outer splice()
  )                       // end of map()

1
"Я хотів би подякувати методу .splice () за ..." Cue PPCG Music of Oscar ... :)
Час Браун

Більш правильно, зовнішній виклик сплайсу отримує відповідно 3 або 2 аргументи, що змушує його робити правильно.
Ніл

2

Хаскелл, 79 байт

(m:n)#u@(s:t)|m==s=m:n#t|all(/=m)u=m:n#u|(x,_:z)<-span(/=s)n=(x++s:m:z)#u
m#_=m

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

(m:n)#u@(s:t)                 -- m: head of master list
                              -- n: tail of master list
                              -- s: head of subset
                              -- t: tail of subset
                              -- u: whole subset
   |m==s                      -- if m==s
        =m:n#t                -- return 'm' and append a recursive call with 'n' and 't'
   |all(/=m)u                 -- if 'm' is not in 'u'
             =m:n#u           -- return 'm' and append a recursive call with 'n' and 'u'
   |                          -- else (note: 's' is element of 'n')
    (x,_:z)<-span(/=s)n       -- split 'n' into a list 'x' before element 's' and
                              -- a list 'z' after element 's' and
       = (x++s:m:z)#u         -- make a recursive call with
                              -- x++s:m:z as the new master list (i.e. 'm' inserted into 'n' after 's') 
                              -- and 'u'
m # _ = m                     -- if either list is emtpy, return the master list

2

Рубін , 73 68 байт

->a,b{0while b.zip(a&b).find{|m,n|m!=n&&a=a[0..a.index(m)]-[n]|a};a}

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

Як?

  • Перетин між aі bмістить усі елементи b, але в тому ж порядку, як ми їх знаходимоa
  • Отже, якщо ми повторюємо bпаралельно і на перехресті, як тільки знайдемо різницю, ми можемо перенести один елемент.
  • Переміщення виконується шляхом вирізання aположення елемента, який ми знайшли b, потім видалення знайденого нами елемента в перехресті, а потім додавання залишку а.
  • Повторюйте з початку, поки всі елементи bне в потрібному порядкуa

що робить 0 0while?
Іона

Це просто НОП.
ГБ

навіщо це потрібно?
Іона

1
Оскільки порівняння та маніпуляція проводиться в одному блоці, щоб уникнути оголошення змінної перед запуском циклу. Це означає: "нічого не робити, поки операція повернеться істинною", код коротший, ніж "виконувати операцію, поки результат вірний"
GB


1

Perl 6 , 40 байт

{*.permutations.first(*.grep(.any)eq$_)}

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

Блок анонімного коду, який приймає введене викрите (наприклад f(subList)(masterList), і знаходить першу лексографічну перестановку індексів головного списку, де елементи із підсписку знаходяться у правильному порядку.

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

Пояснення:

{*                                     } # Anonymous code block that returns a lambda
  .permutations                          # In all permutations of the master list
               .first(                )  # Find the first permutation
                     (*.grep(.any)       # Where the order of the subset
                                  eq$_   # Is the same as the given order


1

Желе , 9 байт

Œ!iⱮṢƑ¥ƇḢ

Спробуйте в Інтернеті! або Тестовий набір

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

Пояснення

Œ!        | Generate all permutations of the master list
      ¥Ƈ  | Filter including only those where...
  iⱮ      |   the index of each sublist item in this permutation...
     Ƒ    |   is...
    Ṣ     |   in order. 
        Ḣ | Finally take the first item

Це не здається, що це відповідало б правилу "Якщо у головного списку два елементи не в порядку відповідно до списку підмножин, елемент, який знаходиться раніше в головному списку, повинен бути переміщений до найбільш раннього індексу, де він знаходиться в правильне розташування відносно інших елементів у списку підмножин. (тобто відразу після наступного пункту) "
Beefster

@Beefster це працює на тих, що я намагався до цих пір. Я думаю, що впорядкованість перестановок така, що це правильний результат. Раді, що ви виявилися неправильними, якщо є контрприклад.
Нік Кеннеді

@Beefster Я зараз спробував усі ваші приклади, крім жіночих імен та 1..12, і впорядкування результату є правильним.
Нік Кеннеді

2
@Beefster У моїй відповіді є часткове пояснення, чому це працює
Джо Кінг

1

J , 49 байт

[:(<@({:+i.@>:@-/)@i.~C.])^:(>/@i.~)&.>/]|.@;2<\[

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

пояснення

Ми приймаємо підмножину як лівий аргумент, а повне введення як праве.

Ми будемо працювати над кодом з конкретним прикладом для наочності:

5 2 4 f 1 2 3 4 5

Візьміть коробкові вставки розміром два підмножини:

2 <\ [

виробляє:

┌───┬───┐
│5 2│2 4│
└───┴───┘

додайте їх до оригінального введення та перетворіть всю річ:

] |.@;

Ми отримуємо:

┌───┬───┬─────────┐
│2 4│5 2│1 2 3 4 5│
└───┴───┴─────────┘

Вирішення проблеми стає зменшенням праворуч наліво вище. Потрібно лише знайти правильне дієслово, яке потрібно вставити /між елементами.

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

Якщо впорядкування пари буде таким самим, як замовлення на вході, наступне буде оцінено до 0, і ми нічого не зробимо:

^:(>/@i.~)

В іншому випадку він оцінить до 1, і ми застосуємо дієслово зліва від ^:

   {: + i.@>:@-/)@i.~ C. ]

який переміщує лівий елемент праворуч від правого елемента. Цей рух є просто циклічною перестановкою всіх елементів між (і в тому числі) двома розглянутими елементами.

J має примітивне застосування такої циклічної перестановки:

<cyclic permutation definition> C. ]

а решта дієслова не робить нічого, окрім вибору індексів, які нам потрібні для циклу:

{: + i.@>:@-/)@i.~

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

Нарешті ми перезаписуємо результат <@і ми закінчуємо .


0

Желе , 24 байти

i@€MƤFṬœṗƲḊ;JḟF}W€ʋ@¥ṢFị

Спробуйте в Інтернеті! або Тестовий набір

Пояснення

Дядічне посилання, яке приймає підмножину як лівий, а основний список як аргументи праворуч. Наведений нижче приклад використовує 9001, 42, 69, 1337, 420, 99, 255 як головний та 69, 9001, 1337 як підмножину.

i@€                      | Find the index of each subset item in the master list [3, 1, 4]
         Ʋ               | Previous 4 links as a monad
   MƤ                    | Find the index of the maximum for each prefix of this list [1, 1, 3]
     F                   | Flatten (because the previous result are actually each length one lists)
      Ṭ                  | Convert to a boolean list [1,0,1]
       œṗ                | Partition the [3, 1, 4] list before each 1 [[], [3, 1], [4]]
          Ḋ              | Remove the empty first list [[3, 1], [4]]
                    ¥    | Previous two links as a dyad
                  ʋ@     | Previous 4 links as a dyad with reversed arguments
            J            | Sequence along the master list [1, 2, 3, 4, 5, 6, 7]
             ḟF}         | Filter out items in the flattened [3, 1, 4] list
                W€       | Wrap each item as a list [[2], [5], [6], [7]]
           ;             | Concatenate rhis to the [[3, 1], [4]] list
                     Ṣ   | Sort (effectively by first item in each list) [[2], [3, 1], [4], [5], [6], [7]]
                      F  | Flatten
                       ị | Look up in original master list (and implicitly output)

0

C # (Visual C # Interactive Compiler) , 118 байт

a=>b=>{for(int j;b.Any();)foreach(var e in b.Intersect(a.Take(j=a.IndexOf(b.Dequeue())))){a.Remove(e);a.Insert(j,e);}}

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

Використання деяких класів у System.Collections.Genericпросторі імен. Основний - це, List<T>а підмножина - aQueue<T> .

// a: master
// b: subset
a=>b=>{
  // continue until b is empty
  for(int j;b.Any();)
    // iterate over values that are out of order in a
    // per the head of b using loop variable e
    foreach(var e in
      // the out of order values are determined by
      // intersecting remaining values in b with
      b.Intersect(
        // values in a occurring before the current head of b
        // save the position in a to variable j and remove the head of b
        a.Take(j=a.IndexOf(b.Dequeue()))
      )
    ){
      // push back the out of order element in a
      a.Remove(e);
      a.Insert(j,e);
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.