Быстрое извлечение элементов из вложенных списков

это основной вопрос о манипуляции списком в 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


можно использовать Part (стенография [[...]]) для этого :

a[[All, 3]]

a[[All, {1, 2}]]