2014-05-30 25 views
7

Muszę wykonać akcję N razy. Jaki jest najlepszy sposób, aby to zrobić?Jak powtórzyć instrukcję N razy (prosta pętla)

for(uint i=0; i<N; i++) 
    action(); 

foreach(uint i; 0.. N) 
    action(); 

może coś lepszego? Idealnie chciałbym coś takiego na Groovy/Ruby times np

N.times { 
    action(); 
} 

jest to możliwe?

+1

Btw, drugi przykład należy użyć 'foreach' zamiast' for' i rzeczywiście można usunąć 'uint'. Konwencja użyta w D dla iteratorów pętli, których nie trzeba przywoływać w pętli, nazywa je "_". Tak więc staje się "foreach (_; 0 .. N)" – yaz

+0

Naprawdę polecam pobranie bezpłatnego odniesienia i przeczytanie go. Wszystko to odpowiada dość wcześnie w książce. Twoje pierwsze prace. Twoja sekunda byłaby dla _ w 0..N {...}. Trzeci jest możliwy, ale nie jestem pewien, czy przedłużenie czasu jest normalne. Wiem, że jest dokładnie taki przykład w prezentacjach WWDC, Myślę, że Swobodny Swift. –

Odpowiedz

10

Tak, to jest możliwe

import std.stdio; 
import std.traits; 

void foo() 
{ 
    writeln("Do It!"); 
} 

void times(T,N)(N n, T action) if (isCallable!T && isIntegral!N) 
{ 
    static if (ParameterTypeTuple!action.length == 1 
      && isIntegral!(ParameterTypeTuple!action[0])) 
     foreach (i; 0 .. n) 
      action(i); 
    else 
     foreach (i; 0 .. n) 
      action(); 
} 

void main(string[] args) 
{ 
    10.times(&foo); 
    10.times({writeln("Do It!");}); 
    10.times((uint n){writeln(n + 1, " Round");}); 
} 

wersja z argumentami wspierać:

import std.stdio; 
import std.traits; 

void foo() 
{ 
    writeln("Do It!"); 
} 

struct Step { 
    alias n this; 
    size_t n; 
    this(size_t i) 
    { 
     n = i + 1; 
    } 
} 

struct Index { 
    alias n this; 
    size_t n; 
} 

void times(T,N,A...)(N n, T action, A args) if (isCallable!T && isIntegral!N) 
{ 
    alias PTTAction = ParameterTypeTuple!action; 
    static if (PTTAction.length >= 1) 
    { 
     alias FP = PTTAction[0]; 
     static if (is(Index == FP) || is(Step == FP)) 
      foreach (i; 0 .. n) 
       action(FP(i), args); 
     else 
      action(args); 
    } 
    else 
     foreach (i; 0 .. n) 
      action(); 
} 

void main(string[] args) 
{ 
    10.times(&foo); 
    10.times({writeln("Do It!");}); 
    10.times((Step n){writeln(n, " Step");}); 
    10.times((Index n, string msg){writeln(n, msg);}, " Index"); 
    stdin.readln; 
} 

UPDATE:

dla lepszej wydajności można użyć aliasu szablonu parametr działania:

void times(alias action,N)(N n) if (isCallable!action && isIntegral!N) 
{ 
    static if (ParameterTypeTuple!action.length == 1 
      && isIntegral!(ParameterTypeTuple!action[0])) 
     foreach (i; 0 .. n) 
      action(i); 
    else 
     foreach (i; 0 .. n) 
      action(); 
} 

void main(string[] args) 
{ 
    10.times!(foo); 
    10.times!({writeln("Do It!");}); 
    10.times!((uint n){writeln(n + 1, " Round");}); 
} 
+0

OK, dziękuję :-) Zwłaszcza pierwsza wersja jest naprawdę łatwa do naśladowania i bardzo mi się podoba. – Parobay

+0

Czy możesz napisać, dlaczego wydajność może być lepsza? – Parobay

+0

Ponieważ przekazywanie według nazwy (alias akcji) nie wymaga działania dereferencyjnego. Ale nie jestem pewien. I może jest więcej powodów, więc byłoby interres, sprawiają, że to osobne pytanie. – Kozzi11

4

Być może coś takiego?

void loop(int n, void delegate() func) 
{ 
    foreach (i; 0 .. n) 
    { 
     func(); 
    } 
} 

Zastosowanie:

loop(10, {   
    writeln("Hello World!"); 
});