Сортування вкладеного списку


23

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

Візьмемо цей список як приклад:

((5, 2), 2, 7, (2, 1, (3, 4)), 9)

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

Отже, пріоритети всіх елементів глибини 1 :

 (  7 )  2  7  (    3       )  9
((5, 2), 2, 7, (2, 1, (3, 4)), 9)

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

 2  (     3      )  (  7 )  7  9
(2, (2, 1, (3, 4)), (5, 2), 7, 9) 

Повторіть для кожного списку. Тож у цьому підсписі

(2, 1, (3, 4))

Наші пріоритети виглядають так:

 2  1  (  7  )
(2, 1, (3, 4))

Так відсортовано, це виглядає так:

(1, 2, (3, 4))

(3, 4)вже відсортовано, тому ми закінчили. Повторіть, для (5, 2)чого результат, (2, 5)і ми готові! Наш остаточний список:

(2, (1, 2, (3, 4)), (2, 5), 7, 9) 

Правила:

  • Дуже сумнівно, але про всяк випадок, якщо у Mathematica є щось для цього, вкладений список впорядкованих вбудованих файлів не допускається. Регулярні функції сортування будуть дозволені.

  • Введення / виведення може бути в будь-якому розумному форматі.

  • Кожен підспис містить мінімум одне число чи список. Крім того, до списків можна вкласти декілька рівнів. Наприклад, в має пріоритет 0, так як вона має тільки підсписки ньому. (1, 2, (((3))))(((3)))

  • Недійсні списки (не збігаються круглі дужки, не числа, неправильні типи дужок, негативні числа тощо) призводять до не визначеної поведінки.

Тест вводу / виводу:

(1, 2, 3) ---> (1, 2, 3)

(1, 2, 6, 3, 9, 8) ---> (1, 2, 3, 6, 8, 9)

(4, 3, (2), (1)) ---> ((1), (2), 3, 4)

(4, 3, (2), ((1))) ---> (((1)), (2), 3, 4)

(5, (1, 2, (9, 8))) ---> ((1, 2, (8, 9)), 5)

(3, (1, 2), (2, 1)) ---> (3, (1, 2), (1, 2))

(3, (1, 2, (99)), (2, 1, (34))) ---> (3, (1, 2, (99)), (1, 2, (34)))

(7, 2, (1, (9, 12)), (4, 3, 2, (1, 2))) ---> ((1, (9, 12)), 2, 7, (2, 3, (1, 2), 4))

Найкоротша відповідь у байтах виграє.


Чи можна вважати, що числа є цілими числами?
— isaacg

@isaacg Так, можна.
— DJMcMayhem

Відповіді:


5

Желе, 13 байт

fFSµ€Ụị߀µ¹<?

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

Як це працює

fFSµ€Ụị߀µ¹<?  Main link. Input: A (list)

   µ€          Apply the chain to the left to each item B in A.
 F             Flatten B.
f              Filter; intersect B with flattened B, yielding a list.
               This returns the numbers in B if B is a list, [B] if B is a number.
  S            Compute the sum of the resulting list.
     Ụ         Sort the indices of A according to the computed sums.
       ߀      Recursively apply the main link to each B in A.
      ị        Retrieve the items of the list (right) at those indices (left).
         µ     Convert the preceding chain into a single link.
            ?  If:
           <     A compared with itself is truthy:
                   Execute the link to the left.
          ¹      Else, apply the identity function to A.

Якщо порівнювати число ( <) з самим собою, то виходить 0 (хибний), але порівнюючи не порожній список із самим собою, виходить список 0 (s), тому <його можна використовувати для відрізнення чисел від списків.


0 - помилково, але поле 0s - це True, але порожнє поле - False. Цікаво, як працює Python. : P
— кіт

Виглядає мені як 25 байт (коли закодовано в UTF-8).
— Ротсор

@Rotsor Це звучить правильно. Однак Jelly використовує користувацьку кодову сторінку, що кодує всі 256 символів, які вона розуміє як окремі байти.
— Денніс

17

Пітон 2, 114 101 78 73 62 байт

k=lambda t:t*(t<[])or t.sort(key=k)or sum(z for z in t if[]>z)

Я знав, що є кращий спосіб відфільтрувати списки.

Сортування списку пітонів (та його підспісів) на місці.

https://eval.in/540457 дякує @tac за те, що повідомив про місцеві рішення, є прийнятними, а @xnor + @feersum - для подальших оптимізацій!


1
Деякі більш оптимізації: k=lambda t:t*(t<[])or sum(z for z in t if[t.sort(key=k)]>z).
— xnor

@xnor Я думаю, що рішення не зовсім правильне: eval.in/540447 . У цьому прикладі ми повторюємось до першого підспису і захоплюємо початковий zз нього 5. Потім в умовному порядку сортуємо список, який ми повторюємо (!), Тож коли ми захопимо наступний z, це ТАКОЖ 5, що приводить до суми 10. Потім сортуємо зовнішній список за допомогою цих клавіш і отримуємо [6, [1, 5]], що неправильно як "Якщо є краватка, ви повинні зберегти той самий порядок, що і вихідний список. " Цікавим є те, що ми sortобидва списки викликаємо два рази, тому це відбувається лише на рівних клавішах: якби підпис був меншим, він би відновлювався.
— Орез

Хороший улов. Смішно, що ітерація триває за відсортованим зараз списком. Я відчуваю, що все-таки повинен бути коротший спосіб дотримуватися Noneрезультатів t.sort(key=k), але я цього не бачу.
— xnor

False0 для цілей +і розширенням, sum. Не можу придумати, як це економить байти.
— CalculatorFeline

@CatsAreFluffy list.sortповертається None, ні False.
— Денніс

4

Луа, 172 байти

function p(a)if type(a)~="table"then return a end s(a)local t=0 for i,v in next,a do t=t+p(v)end return t end
function s(t)table.sort(t,function(a,b)return p(a)<p(b)end)end

Функція sсортує таблицю Lua (структуру даних, яка служить списком серед іншого в Lua) за місцем відповідно до правил.


Мені подобається, як type(a)повертає струну
— кіт

Нарешті відповідь, використовуючи Lua.
— Лина монашка

3

Математика, 50 байт

#0/@SortBy[#,Tr@Cases[#,_Integer,{0,1}]&]~Check~#&

Простий рекурсивний метод, який використовує SortBy. Ігноруйте повідомлення.


3

Haskell, 160 151 135 байт

import Data.List
data T=N Int|T[T]deriving Show
p(N x)=x
p(T t)=sum$[x|N x<-t]
f(N x)=N x
f(T t)=T$sortBy((.p).compare.p)$map f$t

Перша проблема - це вкладені списки. Haskell вимагає, щоб усі елементи списку були одного типу; зокрема ціле число та список цілих чисел не є одним типом. Іншими словами, список змінних вкладених не список, це дерево троянд!

Отже, спочатку ми повинні визначити тип даних для троянди:

data T = N Int | T [T]

(Строго, deriving Showце потрібно лише в тому випадку, якщо ви хочете побачити результати. Але це технічність.) Маючи таке визначення, ми можемо написати список, наприклад (1, 2, (3, 4)),

T [N 1, N 2, T [N 3, N 4]]

що значно менш читабельно. Але що б там не було; це тривіальний, механічний переклад. Префікс кожного числа з Nі кожного піддіречка T.

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

p (N x) = x
p (T t) = sum $ map q t

q (N x) = x
q _     = 0

Якби ми підсумовували всі субелементи, тоді qне було б потреби існувати, зберігаючи величезну кількість символів. Ну добре!

Edit: На насправді, кілька commentors вказують на те , що ви можете уникнути з qдопомогою списку розуміння: [ x | N x <- t]. Гарний дзвінок, хлопці!

(Насправді, pне потрібно було б і існувати; у нас може бути компілятор, який автоматично генерує Ordекземпляр для нас у жмені символів, і ця реалізація за замовчуванням відповідала б специфікації.)

Нарешті, нам потрібно рекурсивно зазначити всі під деревами та сортувати їх:

f (N x) = N x
f (T t) = T $ sortBy (\ x y -> compare (p x) (p y)) $ map f $ t

Тобто fсортує дерево, рекурсивно застосовуючи себе до всіх елементів ( map f), а потім викликаючи sortByфункцію для сортування верхнього рівня. Перший рядок говорить про те, що сортування числа не робить нічого, і це необхідно для припинення рекурсії.


2
sortBy (\ x y -> compare (p x) (p y))просто sortOn p. Використовуйте версію інфіксной карт в p: sum$q<$>t.
— німі

@nimi Де sortOnвизначено? Я завжди хотів знати ...
— MathematicalOrchid


2
ви можете все-таки обрізати 16 байт за допомогою трюку розуміння списку p(T t)=sum[x|N x<-t]та data T=N Int|T[T]deriving Show. :)
— Буде Несс

1
Ви включили 2 байти для кожного нового рядка у свій рахунок? Я думаю, нам дозволено вважати їх синглами . Крім того, немає необхідності $в sum$[x|N x<-t]. Отже, 135-5-1 = 129. :)
— Буде Несс

2

CLISP, 380 байт

(defun q(L)(if(null L)L(append(append(q(car(s(cdr L)(car L))))(list(car L)))(q(cadr(s(cdr L)(car L))))))))(defun s(L E)(if(not(atom(car L)))(setq L(cons(q(car L))(cdr L))))(cond((null L)'(nil nil))((<(v(car L))E)(list(cons(car L)(car(s(cdr L)E)))(cadr(s(cdr L)E))))(T(list(car(s(cdr L)E))(cons(car L)(cadr(s(cdr L)E)))))))(defun v(L)(if(atom L)L(apply'+(remove-if-not #'atom L))))

Викличте функцію q зі списком.

Я пізній ноб, будь ласка, не вбивайте мене ^^


Ха-ха, я сподівався, що хтось зробить це в ліс!
— DJMcMayhem

1

Pyth, 15 байт

L?sIbbossI#NyMb

Тестовий набір

Рекурсивна функція, яка працює наступним чином:

L?sIbbossI#NyMb
L                  define y(b):
 ?sIb              If b is an integer:          (invariant under the s function)
     b             Return it.
            yMb    Else, apply y recursively to all of the elements of b,
      o            Then sort b by
        sI#N       For each element, the elements of that list that are integers.
                   This is luckily a nop on integers.
       s           Summed.

1

Java, 219 байт

import java.util.*;List f(List l){l.sort(Comparator.comparing(o->{if(o instanceof Integer)return(Integer)o;f((List)o);return((List) o).stream().filter(i->i instanceof Integer).mapToInt(i->(Integer)i).sum();}));return l;}

З розривами рядків:

import java.util.*;
List f(List l){
    l.sort(Comparator.comparing(o -> {
        if (o instanceof Integer)
            return (Integer) o;
        f((List) o);
        return ((List) o).stream().filter(i -> i instanceof Integer).mapToInt(i -> (Integer) i).sum();
    }));
    return l;
}

Йде багато кастингу, який дійсно набирає кількість байтів. : P

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

Спробуйте тут .


1
Ось така сама техніка в 154 байтахint f(List l){l.sort(Comparator.comparing(o->o instanceof Integer?(int)o:f((List)o)));return l.stream().mapToInt(o->o instanceof Integer?(int)o:0).sum();}
— Андреас

Я думаю, що є ще багато чого, щоб вичавити.
— Андреас

Але є кілька проблем: ви не можете явно конвертувати подібне Objectдо intцього, а виклик, схоже, вимагає виведення списку.
— ТНТ

Ви фактично зберігаєте 1 байт, змінюючи instanceof, щоб перевірити список замість Integer. Ціле число - 7 байт без фігурних фігурних дужок, але список - 6 байт.
— Синій

@TNT Ви можете кинути об'єкт примітиву в Java 1.7 або вище. Звичайно, якщо об’єкт недійсний, ви отримаєте npe. Я не бачу жодних проблем із сортуванням списку на місці, проблема, схоже, не відповідає безпосередньо цьому питанню.
— Андреас

0

JavaScript (ES6), 86 байт

f=a=>a.map?a.map(f).sort((a,b)=>p(a)-p(b),p=a=>a.map?a.map(a=>t+=a.map?0:a,t=0)|t:a):a

Весь цей масив перевіряє :-(


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