Сортировать вложенный список

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))

Кратчайший ответ в байтах побеждает.

DJMcMayhem
источник
Можно ли считать числа целыми числами?
Исаак
@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 (правда), поэтому <может использоваться для различения чисел от списков.

Деннис
источник
0 - Ложь, но поле 0 - Истина, а пустое - Ложь. Интересно, как работает Python. : P
кот
Похоже, 25 байтов (при кодировании в UTF-8) для меня.
Роцор,
@ Ротсор Это звучит примерно так. Однако Jelly использует пользовательскую кодовую страницу, которая кодирует все 256 символов, которые она понимает как отдельные байты.
Денис
17

Python 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)

Я знал, что есть лучший способ отфильтровать списки.

Сортирует список Python (и его подсписки) на месте.

https://eval.in/540457 благодарим @tac за сообщение о том, что решения на месте приемлемы, и @xnor + @feersum за дальнейшую оптимизацию!

Orez
источник
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

Lua, 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) в соответствии с правилами.

Trebuchette
источник
Я люблю, как type(a)возвращает строку
кошка
Наконец ответ с использованием Lua.
Утренняя монахиня
3

Mathematica, 50 байтов

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

Простой рекурсивный метод, который использует SortBy. Игнорировать сообщения.

LegionMammal978
источник
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функцию для сортировки верхнего уровня. Первая строка говорит, что сортировка числа ничего не делает, и это необходимо для завершения рекурсии.

MathematicalOrchid
источник
2
sortBy (\ x y -> compare (p x) (p y))это просто sortOn p. Используйте версию инфиксной карт в p: sum$q<$>t.
Ними
@nimi Где sortOnопределяется? Я всегда хотел знать ...
MateticOrchid
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 со списком.

Я шучу, пожалуйста, не убивай меня ^^

Joba
источник
Ха-ха, я надеялся, что кто-нибудь сделает это за lisp!
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.
isaacg
источник
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;
}

Происходит много кастингов, которые действительно увеличивают количество байтов. :П

Целочисленные значения подаются в компаратор, а вложенные списки сортируются в первую очередь, прежде чем сумма только целых значений передается компаратору. Эти значения определяют то, как Компаратор определяет свою позицию в списке при его сортировке.

Попробуй это здесь .

тротил
источник
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подобное, и проблема, похоже, требует вывода списка.
TNT
Вы фактически экономите 1 байт, изменяя instanceof для проверки List вместо Integer. Целое число составляет 7 байт без фигурных скобок, но список равен 6 байтам.
Blue
@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
кот