Быстрое извлечение элементов из вложенных списков
это основной вопрос о манипуляции списком в Mathematica. У меня есть большой список, где каждый элемент имеет следующую схематическую форму: {List1,List2, Number}. Например,
a = {{{1,2,3},{1,3,2},5},{{1,4,5},{1,0,2},10},{{4,5,3},{8,3,4},15}}}
.
Я хочу сделать новые списки, которые имеют только некоторые части из каждого подсписка. Например., выберите третий элемент из каждого подлиста, чтобы дать {5,10,15} из вышеизложенного. Или отбросьте третий элемент для возврата {{{1,2,3},{1,3,2}},{{1,4,5},{1,0,2}},{{4,5,3},{8,3,4}}}.
Я могу сделайте это с помощью команды table для создания новых списков, например,
Table[a[[i]][[3]],{i,1,Length[a]}
но мне было интересно, есть ли более быстрый способ, который будет работать на больших списках.
3 ответов
в Mathematica версии 5 и выше вы можете использовать ключевое слово All несколькими способами, чтобы указать обход списка.
например, вместо вашей таблицы вы можете написать
a[[All,3]]
здесь Mathematica преобразует все во все приемлемые индексы для первого измерения, а затем принимает 3-е из следующего измерения.
обычно это более эффективно, чем сделать цикл с языком программирования Mathematica. Это действительно хорошо для однородное списки, где вещи, которые вы хотите выбрать или сканировать всегда существует.
еще одна эффективная нотация и ярлык является;; синтаксис:
a[[ All, 1 ;; 2]]
будет сканировать первый уровень a и принимать все от 1-го до 2-го элемента каждого подсписка, точно так же, как ваш второй случай.
на самом деле все и ;; могут быть объединены в любое количество уровней. ;; может даже использоваться аналогично любому итератору в Система Mathematica:
a[[ start;;end;;step ]]
будет делать то же самое, что
Table[ a[[i]], {i,start,end,step}]
и вы можете опустить один из start, end или step, он заполняется по умолчанию 1, Length [(неявного списка)] и 1.
еще одна вещь, которую вы, возможно, захотите найти в справке Mathematica, - это ReplacePart
и MapAt
которые позволяют программную замену структурированных выражений. Ключевая вещь, чтобы использовать это эффективно, что в ReplacePart вы можете использовать шаблоны чтобы указать координаты вещей, которые будут заменены, и вы можете определить функции для их применения.
пример с вашими данными
ReplacePart[a, {_, 3} -> 0]
заменит каждую 3-ю часть каждого подсписка на 0.
ReplacePart[a, {i : _, 3} :> 2*a[[i, 3]]]
удвоит каждую 3-ю часть каждого подсписка.
как предполагают авторы, подходы, основанные на части, нуждаются в хорошо сформированных данных, но случаи построены для надежного разделения списков:
используя ваш a,
a = {{{1, 2, 3}, {1, 3, 2}, 5}, {{1, 4, 5}, {1, 0, 2},
10}, {{4, 5, 3}, {8, 3, 4}, 15}};
Cases[a,{_List,_List,n_}:>n,Infinity]
{5, 10, 15}
другие части записи могут быть извлечены аналогичными формами.
частично основанные подходы будут кляп на плохо сформированных данных, таких как:
badA = {{{1, 2, 3}, {1, 3, 2}, 5}, {{1, 4, 5}, {1, 0, 2},
10}, {{4, 5, 3}, {8, 3, 4}, 15}, {baddata}, {{1, 2, 3}, 4}};
badA[[All,3]]
{{{1, 2, 3}, {1, 3, 2}, 5}, {{1, 4, 5}, {1, 0, 2},
10}, {{4, 5, 3}, {8, 3, 4}, 15}, {baddata}, {{1, 2, 3},
4}}[[All, 3]]
, но случаи будут пропускать мусор, работая только на соответствующих данных
Cases[badA, {_List, _List, s_} :> s, Infinity]
{5, 10, 15}
hth,
Фред Klingener