Цикл foreach в Mathematica

typedef typename Tail::inUnion dummy;

Однако я не уверен, что реализация inUnion верна. Если я правильно понимаю, этот класс не должен быть создан, поэтому вкладка «fail» никогда не будет автоматически терпеть неудачу. Возможно, было бы лучше указать, находится ли тип в объединении или нет с простым булевым значением.

template  struct Contains;

template 
struct Contains >
{
    enum { result = Contains::result };
};

template 
struct Contains >
{
    enum { result = true };
};

template 
struct Contains
{
    enum { result = false };
};

PS: Посмотрите на Boost :: Variant

PS2: посмотрите на typelists , особенно в книге Андрея Александреску: Modern C ++ Design

17
задан 16 revs, 2 users 97% 17 April 2019 в 22:03
поделиться

6 ответов

Встроенное Scan в основном делает это, хотя это более ужасно:

    Scan[Print[#]&, {1,2,3}]

Это особенно ужасно, когда Вы хотите к destructure элементы:

    Scan[Print[#[[1]] * #[[2]]]&, {{1,10}, {2,20}, {3,30}}]

следующая функция избегает уродства путем преобразования pattern к body для каждого элемента list.

SetAttributes[ForEach, HoldAll];
ForEach[pat_, lst_, bod_] :=  Scan[Replace[#, pat:>bod]&, Evaluate@lst]

, который может использоваться в качестве в примере в вопросе.

пз: принятый ответ побудил меня переключаться на это, которое является тем, что я использовал, с тех пор и это, кажется, работает отлично (за исключением протеста, который я добавил к вопросу):

SetAttributes[ForEach, HoldAll];             (* ForEach[pattern, list, body]   *)
ForEach[pat_, lst_, bod_] := ReleaseHold[    (*  converts pattern to body for  *)
  Hold[Cases[Evaluate@lst, pat:>bod];]];     (*   each element of list.        *)
7
ответ дан 30 November 2019 в 12:51
поделиться

Встроенная функция Карты делает точно, что Вы хотите. Это может использоваться в подробной форме:

Карта [Печать, {1,2,3}]

или стенография

Печать / {1,2,3}

В Вашем втором случае, Вы использовали бы "Печать [Времена @@#]& / {{1,10}, {2,20}, {3,30}}"

я рекомендовал бы читать справку Mathematica на Карте, MapThread, Подал бы заявку, и Функция. Они могут взять бит привыкания к, но как только Вы, Вы никогда не будете хотеть возвращаться!

3
ответ дан 30 November 2019 в 12:51
поделиться

Вот небольшое улучшение, основанное на последнем ответе дривов, которое позволяет задавать шаблон без пробела (делая синтаксис похожим на другие функции, такие как Table или Do) и которое использует аргумент уровня Cases

SetAttributes[ForEach,HoldAll];
ForEach[patt_/; FreeQ[patt, Pattern],list_,expr_,level_:1] :=
   Module[{pattWithBlanks,pattern},
      pattWithBlanks = patt/.(x_Symbol/;!MemberQ[{"System`"},Context[x]] :> pattern[x,Blank[]]);
      pattWithBlanks = pattWithBlanks/.pattern->Pattern;

      Cases[Unevaluated@list, pattWithBlanks :> expr, {level}];
      Null
   ];

Испытания:

ForEach[{i, j}, {{1, 10}, {2, 20}, {3, 30}}, Print[i*j]]
ForEach[i, {{1, 10}, {2, 20}, {3, 30}}, Print[i], 2]
2
ответ дан 30 November 2019 в 12:51
поделиться

В более новых версиях Mathematica (6.0+) есть обобщенные версии Do [] и Table [], которые делают почти то, что вы хотите, за счет использования альтернативной формы аргумента итератора. Например,

Do[
  Print[i],
  {i, {1, 2, 3}}]

точно такой же, как ваш

ForEach[i_, {1, 2, 3,},
  Print[i]]

. Альтернативно, если вам действительно нравится конкретный синтаксис ForEach, вы можете создать функцию HoldAll, которая его реализует, например:

Attributes[ForEach] = {HoldAll};

ForEach[var_Symbol, list_, expr_] :=
  ReleaseHold[
    Hold[
      Scan[
        Block[{var = #},
         expr] &,
      list]]];

ForEach[vars : {__Symbol}, list_, expr_] :=
  ReleaseHold[
    Hold[
      Scan[
        Block[vars,
          vars = #;
          expr] &,
      list]]];

Здесь в качестве имен переменных используются символы, а не шаблоны, но именно так работают различные встроенные управляющие структуры, такие как Do [] и For [].

Функции HoldAll [] позволяют собрать довольно широкий набор настраиваемых структур управления. ReleaseHold [Hold [...]] обычно самый простой способ собрать кучу кода Mathematica для последующего анализа, а Block [{x = #}, ...] & позволяет привязать переменные в теле выражения к любые ценности, которые вы хотите.

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

ForEach[patt_, list_, expr_] := 
  ReleaseHold[Hold[
     Module[{f}, 
       f[patt] := expr; 
       Scan[f, list]]]]

На этом этапе, однако, я думаю, что вам может быть лучше построить что-то сверху of Cases.

ForEach[patt_, list_, expr_] :=
  With[{bound = list},
    ReleaseHold[Hold[
       Cases[bound,
         patt :> expr]; 
       Null]]]

Мне нравится делать Null явным, когда я подавляю возвращаемое значение функции. РЕДАКТИРОВАТЬ : я исправил ошибку, указанную ниже; Мне всегда нравится использовать With для интерполяции вычисленных выражений в формы Hold * .

m подавление возвращаемого значения функции. РЕДАКТИРОВАТЬ : я исправил ошибку, указанную ниже; Мне всегда нравится использовать With для интерполяции вычисленных выражений в формы Hold * .

m подавление возвращаемого значения функции. РЕДАКТИРОВАТЬ : я исправил ошибку, указанную ниже; Мне всегда нравится использовать With для интерполяции вычисленных выражений в формы Hold * .

7
ответ дан 30 November 2019 в 12:51
поделиться

В Mathematica есть функции отображения, поэтому допустим, у вас есть функция Func , принимающая один аргумент. Затем просто напишите

Func /@ list

Print /@ {1, 2, 3, 4, 5}

Возвращаемое значение - это список функций, применяемых к каждому элементу в списке.

PrimeQ /@ {10, 2, 123, 555}

вернет {False, True, False, False}

1
ответ дан 30 November 2019 в 12:51
поделиться

Я на много лет опоздал на вечеринку, и это, возможно, больше ответ на «мета-вопрос», но то, с чем многим людям изначально трудно при программировании в Mathematica (или других функциональных языках) подходит к проблеме с функциональной, а не структурной точки зрения. Язык Mathematica имеет структурные конструкции, но по своей сути он функциональный.

Рассмотрим свой первый пример:

ForEach[i_, {1,2,3},
  Print[i]
]

Как указали несколько человек, функционально это можно выразить как Scan [Print, {1,2,3}] или Print / @ {1 , 2,3} (хотя вам следует отдать предпочтение Сканировать , а не Map , когда это возможно, как объяснялось ранее, но иногда это может раздражать, поскольку нет инфиксного оператора для Сканирование ).

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

ForEach[{i_, j_}, {{1,10}, {2,20}, {3,30}},
  Print[i*j]
]

... который более интересен с функциональной точки зрения.

Одно из возможных функциональных решений - вместо этого использовать замену списком, например:

In[1]:= {{1,10},{2,20},{3,30}}/.{i_,j_}:>i*j
Out[1]= {10,40,90}

...но если бы список был очень большим, это было бы излишне медленно, поскольку мы выполняем так называемое «сопоставление с образцом» (например, ищем экземпляры {a, b} в списке и присваиваем их i и j ) без необходимости.

Учитывая большой массив из 100 000 пар, array = RandomInteger [{1, 100}, {10 ^ 6, 2}] , мы можем посмотреть на некоторые моменты времени:

Замена правил довольно быстро:

In[3]:= First[Timing[array /. {i_, j_} :> i*j;]]
Out[3]= 1.13844

... но мы можем сделать немного лучше, если воспользуемся структурой выражения, где каждая пара действительно List [i, j] , и применим Times в качестве главы каждой пары, превращая каждый {i, j} в Times [i, j] :

In[4]:= (* f@@@list is the infix operator form of Apply[f, list, 1] *)
    First[Timing[Times @@@ array;]]
Out[4]= 0.861267

Как используется в реализации ForEach [.. .] выше, Cases явно неоптимальны:

In[5]:= First[Timing[Cases[array, {i_, j_} :> i*j];]]
Out[5]= 2.40212

... поскольку Cases выполняет больше работы, чем просто замена правила, имея необходимость создания вывода совпадающих элементов один -одним. Оказывается, мы можем сделать много лучше, если разложим задачу по-другому и воспользуемся преимуществом того факта, что Times является Listable и поддерживает векторизованные операции.

Атрибут Listable означает, что функция f будет автоматически обрабатывать любые аргументы списка:

In[16]:= SetAttributes[f,Listable]
In[17]:= f[{1,2,3},{4,5,6}]
Out[17]= {f[1,4],f[2,5],f[3,6]}

Итак, поскольку Times является Listable , если бы вместо этого у нас были пары чисел как два отдельных массива:

In[6]:= a1 = RandomInteger[{1, 100}, 10^6];
        a2 = RandomInteger[{1, 100}, 10^6];

In[7]:= First[Timing[a1*a2;]]
Out[7]= 0.012661

Вау , намного быстрее! Даже если входные данные не были представлены в виде двух отдельных массивов (или у вас более двух элементов в каждой паре), мы все равно можем сделать что-то оптимальное:

In[8]:= First[Timing[Times@@Transpose[array];]]
Out[8]= 0.020391

Мораль этого эпоса не в том, что ForEach не является ценной конструкцией в целом или даже в системе Mathematica, но вы можете часто получать те же результаты более эффективно и элегантно, работая в функциональном, а не в структурном мышлении.

7
ответ дан 30 November 2019 в 12:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: