Выбор карты для условного запроса в Mathematica - PullRequest
4 голосов
/ 04 июня 2011

Используя следующий список,

list = {{a, b, c, d}, {1, 2, 3, 4}, {5, 6, 7, 8}};

Можно ли выбрать списки, где второе значение> 3. Желаемый выход ниже

{5, 6, 7, 8}

настройка следующего кода, который в настоящее время извлекает все значения> 2 в списке

Select[#, # > 2 &] & /@ list[[2 ;;]

Сложные решения для запросов можно найти здесь Условное манипулирование данными в Mathematica

Ответы [ 5 ]

7 голосов
/ 04 июня 2011

В качестве альтернативы, используя Select

Select[list, #[[2]] > 3 &]

Выход

{{5, 6, 7, 8}}
6 голосов
/ 05 июня 2011

Скорость сравнения различных решений

Интересно, что Select всегда работает быстрее с распакованными массивами, а для больших массивов разница составляет порядка одного порядка! Нажмите на следующую таблицу, чтобы увеличить:

Table

Код для проверки времени:

solutions = Hold[
   Select[list, #[[2]] > 3 &],
   Cases[list, _List?(#[[2]] > 3 &)],
   Cases[list, x_List /; x[[2]] > 3],
   Cases[list, {_, x_, ___} /; x > 3],
   Cases[list, {_, _?(# > 3 &), ___}],
   Cases[list, {x___} /; List[x][[2]] > 3],
   Pick[list, UnitStep[list[[All, 2]] - 3], 1],
   Pick[list, # > 3 & /@ list[[All, 2]]]
   ];
testCases = Hold[
   {"Packed Reals", RandomReal[{0, 5}, {dim, dim}]},
   {"Unpacked Reals", 
    Developer`FromPackedArray@RandomReal[{0, 5}, {dim, dim}]},
   {"Packed Integers", RandomInteger[{0, 5}, {dim, dim}]},
   {"Unpacked Integers", 
    Developer`FromPackedArray@RandomInteger[{0, 5}, {dim, dim}]},
   {"Rationals", 
    Rationalize[#, .001] & /@ RandomReal[{0, 5}, {dim, dim}]}
   ];
timing := 
  Function[Null, 
   If[(time = First[Timing[Do[#;, {n}]]]) < .3, 
     Print["Too small timing for ", n, " iterations (dim=", dim, 
      ") of ", HoldForm[#], ": ", time, " seconds!"]; time, time]/n, 
   HoldFirst];
generateTable := 
 Labeled[TableForm[
   Transpose@
    Table[list = testCases[[i, 2]]; 
     tmgs = List @@ (timing /@ solutions); 
     d = Last@MantissaExponent[Min[tmgs]] - 3; 
     Row[{Round[10^-d*#], ".\[Times]", Superscript[10, d]}] & /@ 
      tmgs, {i, 1, Length[testCases]}], 
   TableHeadings -> {List @@ (HoldForm /@ solutions), 
     List @@ testCases[[All, 1]]}, TableAlignments -> Right], 
  Row[{"Average timings for ", dim, "\[Times]", dim, " list"}], Top]

Column[{dim = 5; n = 30000; generateTable, dim = 100; n = 3000; 
  generateTable, dim = 1000; n = 150; generateTable}, Left, 1, 
 Frame -> All, FrameStyle -> Gray]
6 голосов
/ 04 июня 2011

В этом случае Select - самый простой метод, но Pick также может быть полезен в связанных проблемах.

list = {{a, b, c, d}, {1, 2, 3, 4}, {5, 6, 7, 8}};

Pick[list, #>3& /@ list[[All, 2]] ]

Для объяснения, Pick принимает два списка (или вложенных списка) изтой же формы и возвращает каждый элемент первого, для которого соответствующий элемент второго равен True.(Он также может принимать третий аргумент для сопоставления с элементами, отличными от True.)

Здесь второй столбец извлекается с помощью list[[All, 2]], а затем тест #>3& сопоставляется с каждым элементом.Затем он используется в качестве списка выбора.


Отвечая на комментарии 500 с просьбой обобщить метод Select:

selectByColumn[array_, index_, value_, range_] :=
  Select[array, #[[index]] > value &][[All, range]]

Это позволяет указать:

  • array: входной массив для извлечения из
  • index: индекс столбца для сравнения
  • value: значение для сравнения с
  • range: Part спецификация для извлечения из каждой строки результатов
4 голосов
/ 04 июня 2011

Альтернативный синтаксис.Первый элемент пропускается, второй проверяется на> 3, и нас не волнует остальная часть списка:

In[45]:= Cases[list, {_, _?(# > 3 &), ___}]
Out[45]= {{5, 6, 7, 8}}

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

3 голосов
/ 04 июня 2011

EDIT:

Как отметил Алексей, следующие конструкции более математичны в Mathematica, чем в моем предыдущем решении

Cases[list, x_List /; x[[2]] > 2]

и

Cases[list, _List?(#[[2]] > 2 &)]

Одним из решений будет использование Cases

Cases[list, {_, x_, ___} /; x > 2]
Out[1] = {{5, 6, 7, 8}}

Это не полезно, если вы хотите (скажем) проверить, является ли 95-й элемент> 2. Так что это лучший подход, когда вы можете указать позициюлегко:

Cases[list, {x___} /; List[x][[2]] > 2]
Out[2] = {{5, 6, 7, 8}}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...