Вопрос или проблема
У меня в файле есть следующая строка:
[[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 данных в командной строке. Выбор инструмента будет зависеть от вашей предпочтительной рабочей среды и типа данных, с которыми приходится работать.