Как выполнить пользовательскую сортировку

Вопрос или проблема

У меня в файле есть следующая строка:

[[0, [0, '1']], [1, [0, '2']], [2, [0, '3']], [3, [0, '4']]]
[[0, [1, '5']], [1, [1, '6']], [2, [1, '7']], [3, [1, '8']]]
[[0, [2, '9']], [1, [2, '10']], [2, [2, '11']], [3, [2, '12']]]

Есть ли способ отсортировать их по первому символу (0, 1, 2 или 3) во внутреннем элементе списка так, чтобы у меня получилось следующее:

[[0, [0, '1']], [0, [1, '5']],[0, [2, '9']]]
[[1, [0, '2']], [1, [1, '6']],[1, [2, '10']]] 

и так далее?

Ну, это не особенно элегантно, но это сделает то, что вам нужно. По крайней мере, это работает на вашем примере:

perl -ne 'while(s/(\[(\d),\s*\[.+?\]\])//){push @{$k{$2}},$1 . ",";} 
          END{ print "[@{$k{$_}}]\n" for keys(%k)}' file.txt | 
sed 's/,\]$/\]/' | sort

Выполнение вышеприведённой команды на файле с именем file.txt, который содержит строки из вашего примера, даёт следующий результат:

[[0, [0, '1']], [0, [1, '5']], [0, [2, '9']]]
[[1, [0, '2']], [1, [1, '6']], [1, [2, '10']]]
[[2, [0, '3']], [2, [1, '7']], [2, [2, '11']]]
[[3, [0, '4']], [3, [1, '8']], [3, [2, '12']]]

Объяснение

Я не буду объяснять подробно, так как это на самом деле маленькая программа и она использует несколько особенностей Perl. Основная идея скрипта Perl заключается в том, чтобы найти все случаи [\d, [.+?]], где \d – это любое число, а .+?]] – это всё, что до первых ]]. Это фактически собирает все разные подмассивы или кортежи или как бы вы их ни называли и сохраняет их в хеш массивов, чей ключ – это первая цифра, по которой вы хотите отсортировать. После того, как весь файл обработан, он выводит каждый массив хеша. Это вывод самого скрипта:

$ perl -ne 'while(s/(\[(\d),\s*\[.+?\]\])//){push @{$k{$2}},$1 . ",";} 
          END{ print "[@{$k{$_}}]\n" for keys(%k)}' file.txt 
[[1, [0, '2']], [1, [1, '6']], [1, [2, '10']],]
[[3, [0, '4']], [3, [1, '8']], [3, [2, '12']],]
[[0, [0, '1']], [0, [1, '5']], [0, [2, '9']],]
[[2, [0, '3']], [2, [1, '7']], [2, [2, '11']],]

Я разделяю каждый подмассив запятой ,, но это значит, что у меня в конце остаётся лишняя, поэтому я использую sed для её удаления.

$ perl -ne 'while(s/(\[(\d),\s*\[.+?\]\])//){push @{$k{$2}},$1 . ",";} 
>           END{ print "[@{$k{$_}}]\n" for keys(%k)}' file.txt | 
> sed 's/,\]$/\]/' 
[[1, [0, '2']], [1, [1, '6']], [1, [2, '10']]]
[[3, [0, '4']], [3, [1, '8']], [3, [2, '12']]]
[[0, [0, '1']], [0, [1, '5']], [0, [2, '9']]]
[[2, [0, '3']], [2, [1, '7']], [2, [2, '11']]]

Наконец, вы также хотели это отсортировать, но так как они сейчас организованы по их первому символу, простая команда sort справится:

$ perl -ne 'while(s/(\[(\d),\s*\[.+?\]\])//){push @{$k{$2}},$1 . ",";} 
          END{ print "[@{$k{$_}}]\n" for keys(%k)}' file.txt | 
sed 's/,\]$/\]/' | sort
[[0, [0, '1']], [0, [1, '5']], [0, [2, '9']]]
[[1, [0, '2']], [1, [1, '6']], [1, [2, '10']]]
[[2, [0, '3']], [2, [1, '7']], [2, [2, '11']]]
[[3, [0, '4']], [3, [1, '8']], [3, [2, '12']]]

Похоже, что операция, которую вы хотите выполнить, – это “транспонирование”, а не сортировка.

Данные, которые вы представили, выглядят как три массива YAML. Давайте преобразуем их в JSON, просто заменив одинарные кавычки на двойные, а затем используем jq для получения транспонированных данных.

$ tr "'" '"' <file | jq -c -s 'transpose[]'
[[0,[0,"1"]],[0,[1,"5"]],[0,[2,"9"]]]
[[1,[0,"2"]],[1,[1,"6"]],[1,[2,"10"]]]
[[2,[0,"3"]],[2,[1,"7"]],[2,[2,"11"]]]
[[3,[0,"4"]],[3,[1,"8"]],[3,[2,"12"]]]

Если вам нужно вернуть одинарные кавычки, добавьте tr '"' "'" в качестве дополнительного шага в конвейере.

Команда jq выше читает три массива как подмассивы одного массива, выполняет транспонирование и извлекает полученные подмассивы. Вывод записывается в формате “компактного” JSON, по одному массиву на строку.

.

Ответ или решение

Чтобы выполнить упорядочивание пользовательского типа данных, как показано в вашем случае, важно четко понять структуру данных и желаемый результат. В вашем случае у нас имеются вложенные массивы, и целью является их сортировка по первому элементу внутреннего массива.

Теория

Ваша задача в данном случае заключается в том, чтобы выполнить "транспонирование" данных. Этот процесс относится к преобразованию табличных данных, чтобы строки становились столбцами и наоборот. В данном контексте цель заключается в том, чтобы сгруппировать элементы по первому числу во вложенных массивах.

Пример

Предположим, у нас есть данные в следующем виде:

[
    [[0, [0, '1']], [1, [0, '2']], [2, [0, '3']], [3, [0, '4']]],
    [[0, [1, '5']], [1, [1, '6']], [2, [1, '7']], [3, [1, '8']]],
    [[0, [2, '9']], [1, [2, '10']], [2, [2, '11']], [3, [2, '12']]]
]

Желаемый результат:

[
    [[0, [0, '1']], [0, [1, '5']], [0, [2, '9']]],
    [[1, [0, '2']], [1, [1, '6']], [1, [2, '10']]],
    [[2, [0, '3']], [2, [1, '7']], [2, [2, '11']]],
    [[3, [0, '4']], [3, [1, '8']], [3, [2, '12']]]
]

Применение

Для достижения этой цели можно воспользоваться различными инструментами обработки данных. Ваша изначальная идея использовать Perl и sed имеет свои достоинства, но, возможно, более современным подходом было бы использование Python или jq для работы с JSON.

Использование Python:

Пример на Python может выглядеть следующим образом:

import json

data = [
    [[0, [0, '1']], [1, [0, '2']], [2, [0, '3']], [3, [0, '4']]],
    [[0, [1, '5']], [1, [1, '6']], [2, [1, '7']], [3, [1, '8']]],
    [[0, [2, '9']], [1, [2, '10']], [2, [2, '11']], [3, [2, '12']]]
]

# Транспонирование данных
transposed_data = list(map(list, zip(*data)))

# Преобразование в строку JSON для удобного отображения
print(json.dumps(transposed_data, indent=4, ensure_ascii=False))

Этот код сначала использует функцию zip для группировки элементов, а затем преобразует их в список с помощью map и list. В конце концов, результат форматируется как строка JSON для удобного отображения.

Использование jq:

Если ваши данные находятся в подходящем формате JSON, то можно использовать инструмент jq, как было описано в вашем примере:

tr "'" '"' < file | jq -c -s 'transpose[]'

Объяснение:

  • tr "'" '"' заменяет одинарные кавычки на двойные, чтобы данные стали корректным JSON.
  • jq -c -s 'transpose[]' выполняет транспонирование и выводит данные в компактном (сжатом) формате JSON.

Заключение

В зависимости от вашего окружения и предпочтений, вы можете использовать различные подходы и инструменты для достижения желаемого результата. Python предоставляет мощные возможности для работы с многомерными структурами данных, тогда как jq является удобным инструментом для обработки JSON данных в командной строке. Выбор инструмента будет зависеть от вашей предпочтительной рабочей среды и типа данных, с которыми приходится работать.

Оцените материал
Добавить комментарий

Капча загружается...