문제

나는 다음과 같은 것을 원한다 :

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

또는 더 일반적으로, 목록의 임의의 파괴를 위해, 당신은 다음과 같이 반복하고 있습니다.

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

일반적으로 사용하고 싶습니다 Map 또는 다른 순수한 기능적 구조물과 부작용을 사용하는 비 기능적 프로그래밍 스타일을 피합니다. 그러나 여기에 각각의 구조물이 매우 유용하다고 생각하는 예가 있습니다.

상징과 같은 옵션 목록 (규칙)이 있다고 말합니다.

attrVals = {a -> 7, b -> 8, c -> 9}

이제 해시 테이블을 만들고 싶습니다. 그 기호를 그 숫자에 명백히 매핑하는 것을하고 싶습니다. 나는 그렇게 할 수있는 더 깨끗한 방법이 있다고 생각하지 않습니다.

each[a_ -> v_, attrVals, h[a] = v]

추가 테스트 사례

이 예에서는 변수 목록을 변환합니다.

a = 1;
b = 2;
c = 3;
each[i_, {a,b,c}, i = f[i]]

위 후에 {a,b,c} 평가해야합니다 {f[1],f[2],f[3]}. 그것은 두 번째 논쟁을 의미합니다 each 목록이라면 분류되지 않아야합니다.

평가되지 않은 양식이 목록이 아닌 경우 두 번째 인수를 평가해야합니다. 예를 들어:

each[i_, Rest[{a,b,c}], Print[i]]

그것은 값을 인쇄해야합니다 b 그리고 c.

부록: 맞춤을 제대로 수행하려면 지원해야합니다 Break[] 그리고 Continue[]. 어떻게 구현 해야할지 잘 모르겠습니다. 아마도 그것은 어떻게 든 for의 관점에서 구현되어야 할 것입니다. Break[] 그리고 Continue[].

그리고 지금까지 답의 또 다른 문제 : 그들은 먹습니다. Return[]에스. 즉, 함수에서 Foreach 루프를 사용하고 루프 내에서 함수에서 돌아 오려면 할 수 없습니다. Foreach 루프 내부에서 반품을 발행하는 것 같습니다. Continue[]. 이것은 단지 (기다리기 위해) 루프를 위해 나를 던졌습니다.

도움이 되었습니까?

해결책 7

감사합니다 필시 그리고 레오 니드 시프린, 현재 내가 사용하고있는 내용은 다음과 같습니다.

SetAttributes[each, HoldAll];               (* each[pattern, list, body]      *)
each[pat_, lst_List, bod_] :=               (*  converts pattern to body for  *)
  (Cases[Unevaluated@lst, pat:>bod]; Null); (*   each element of list.        *)
each[p_, l_, b_] := (Cases[l, p:>b]; Null); (* (Break/Continue not supported) *)

다른 팁

최신 버전의 Mathematica (6.0+)에는 대체 형태의 반복적 인 인수를 취함으로써 거의 정확하게 원하는 것을 수행하는 Do [] 및 Table []의 일반화 된 버전이 있습니다. 예를 들어,

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

당신과 똑같습니다

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

또는 특정 foreach 구문을 정말로 좋아한다면 다음과 같이 구현하는 홀드 기능을 만들 수 있습니다.

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]]];

이것은 기호를 패턴이 아닌 변수 이름으로 사용하지만 [] 및 [] 작업과 같은 다양한 내장 제어 구조가 방법입니다.

Holdall [] 기능을 사용하면 매우 다양한 사용자 정의 제어 구조를 구성 할 수 있습니다. 릴리스 홀드 [hold [...]]는 일반적으로 나중에 평가할 수있는 수학 코드를 조립하고 [{x = #}, ...]를 차단하는 가장 쉬운 방법입니다. 원하는 가치가 무엇이든.

아래의 Dreeves의 질문에 대한 응답 으로이 접근법을 수정하여 고유 한 기호의 다운 값을 사용하여보다 임의의 파괴를 허용 할 수 있습니다.

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

그러나이 시점에서, 나는 당신이 사례에 무언가를 구축하는 것이 더 나을 것이라고 생각합니다.

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

함수의 반환 값을 억제 할 때 Null을 명시 적으로 만드는 것을 좋아합니다. 편집하다: 나는 아래에 dreeves를 지적한 버그를 수정했다. 나는 항상 사용하는 것을 좋아합니다 With 평가 된 표현을 보간하기 위해 Hold* 형태.

저는 여기 파티에 늦었고, 이것은 아마도 "메타 질문"에 대한 답이 될 것입니다. 그러나 많은 사람들이 Mathematica (또는 다른 기능적 언어)에서 프로그래밍 할 때 처음에는 어려움을 겪고 있습니다. 구조적 관점보다는 기능적입니다. Mathematica 언어는 구조적 구성을 가지고 있지만 핵심에서는 기능적입니다.

첫 번째 예를 고려하십시오.

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

몇몇 사람들이 지적했듯이 이것은 기능적으로 다음과 같이 표현 될 수 있습니다. Scan[Print, {1,2,3}] 또는 Print /@ {1,2,3} (당신은 선호해야하지만 Scan ~ 위에 Map 가능한 경우, 이전에 설명했지만, 이는 Infix 연산자가 없기 때문에 때때로 성가시킬 수 있습니다. Scan).

Mathematica에는 보통 모든 것을 할 수있는 12 가지 방법이 있습니다. 때로는 아름답고 때로는 실망 스럽습니다. 이를 염두에두고 두 번째 예를 고려하십시오.

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) 불필요하게.

10 만 쌍의 큰 배열이 주어지면 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

우와, 조금 더 빨리! 입력이 두 개의 개별 배열로 제공되지 않았더라도 (또는 각 쌍에 2 개 이상의 요소가 있음) 여전히 최적의 작업을 수행 할 수 있습니다.

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

이 서사시의 도덕은 그렇지 않습니다 ForEach 일반적으로 귀중한 구조물이거나 Mathematica에서도 구조적 사고 방식이 아닌 기능적 사고 방식으로 작업 할 때 동일한 결과를 더 효율적이고 우아하게 얻을 수 있습니다.

내장 Scan 기본적으로 이렇게하지만 추악합니다.

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

요소를 파괴하고 싶을 때 특히 추악합니다.

    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.        *)

내장 된 맵 함수는 원하는 것을 정확하게 수행합니다. 긴 형태로 사용할 수 있습니다.

지도 [print, {1,2,3}

또는 짧은 손

print /@ {1,2,3}

두 번째 경우에는 "print [times @@#] &/@{{1,10}, {2,20}, {3,30}}"을 사용합니다.

지도, Mapthread, Apply 및 Function에서 Mathematica 도움말을 읽는 것이 좋습니다. 그들은 조금 익숙해 질 수 있지만 일단 당신이되면 결코 돌아가고 싶지 않을 것입니다!

다음은 공백없이 패턴을 지정할 수있는 Dreeves의 마지막 답변을 기반으로 약간의 개선 사항입니다 (테이블 또는 수행과 같은 다른 기능과 비슷한 구문을 만들고 사례의 레벨 인수를 사용합니다.

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]

Mathematica에는지도 기능이 있으므로 기능이 있다고 가정 해 보겠습니다. Func하나의 논쟁을 취합니다. 그냥 쓰십시오

Func /@ list

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

리턴 값은 인 목록의 각 요소에 적용되는 함수 목록입니다.

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

돌아올 것입니다 {False,True,False,False}

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top