2010-11-03 4 views
2

Il est probablement fonction intégrée ou une meilleure et plus rapide de le faire dans MathematicaY at-il une fonction standard pour cela?

func[l_, g_, f_] := g @@ f @@@ Transpose[{Most[l], Rest[l]}] 

qui peut être utilisé pour faire des choses comme ça

l = {a, b, c, d} 
func[l, Plus, (#1 - #2)^2 &] 

Je ne sais pas le bon nom pour ce genre de fonction. Quelque chose dans un genre de pli-zip.

MISE À JOUR Beaucoup de solutions. Merci à tout le monde.

En utilisant

Partition[l, 2, 1] 

au lieu de

Transpose[{Most[l], Rest[l]}] 

rend certainement plus clair.

J'ai essayé de courir timings sur les fonctions, mais je reçois des résultats étranges:

func1[l_, g_, f_] := g @@ f @@@ Transpose[{Most[l], Rest[l]}] 
func2[l_, g_, f_] := g @@ f @@@ Partition[l, 2, 1] 
func3[l_, g_, f_] := g @@ ListConvolve[{1, 1}, l, {-1, 1}, {}, Times, f] 
func4[l_, g_, f_] := g @@ Thread[f[[email protected], [email protected]]] 
func5[l_, g_, f_] := g @@ f /@ Partition[l, 2, 1] 
func6[l_, g_, f_] := g @@ Thread[f[Most[l], Rest[l]]] 
func7[l_, f_, g_] := Inner[f, Sequence @@ Partition[l, Length[l] - 1, 1], g] 
func8[l_, g_, f_] := g @@ MapThread[f, Partition[l, Length[l] - 1, 1]] 
functions = {func1, func2, func3, func4, func5, func6, func7, func8} 

input = Table[ToExpression["x" <> ToString[i]], {i, 1, 1000000}]; 
inputs = Table[Take[input, i*100000], {i, 1, 10}]; 

Table[ 
    If[i == j == 0, "", 
    If[j == 0, functions[[i]], 
    If[i == 0, Length[inputs[[j]]], 
    Timing[functions[[i]][inputs[[j]]]][[1]]]]], 
    {i, 0, Length[functions]}, {j, 0, Length[inputs]}] // Transpose // TableForm 
+1

Juste un commentaire OT. Pour générer votre grande liste 'input', il est plus rapide d'utiliser' Table [Symbol ["x" <> ToString [i]], {i, 1000000}] 'ou' Array [Symbol ["x" <> ToString [#] ] &, 1000000] 'que' ToExpression [...] '. – Simon

+0

Merci! Je ne le savais pas. – Max

Répondre

6

Si vous voulez quelque chose qui fait double emploi avec exactement les fonctionnalités de votre func, le seul prettyfication je peux penser remplace Transpose[Most[l],Rest[l]] avec Partition:

func2[l_,g_,f_]:[email protected]@[email protected]@@Partition[l,2,1] 

Si vous voulez vraiment quelque chose « construit », vous pouvez pirater sur certains coups de pied ListConvolve pour

func3[l_,g_,f_]:[email protected]@ListConvolve[{1,1},l,{-1,1},{},Times,f] 

Vérification que tous ces travaux:

Through[{func,func2,func3}[l,Plus,(#1-#2)^2&]] 
Out[19]= {(a-b)^2+(b-c)^2+(c-d)^2,(a-b)^2+(b-c)^2+(c-d)^2,(a-b)^2+(b-c)^2+(c-d)^2} 

Enfin, si cela est la réponse que vous cherchez, je vous suggère de calcul par Total[Differences[l]^2]

Out[14]= (-a+b)^2+(-b+c)^2+(-c+d)^2 
+0

Un bel ensemble d'options. 'Differences' est une application spéciale de' ListConvolve', donc il n'a pas besoin de dupliquer la liste comme 'Partition' et' Most, Rest'. Ainsi, il devrait être plus efficace en mémoire. C'est aussi environ 1/3 plus rapide que ma solution. – Simon

+0

@ Simon Mais l'OP a souligné les fonctions générales des éléments de liste contigus. –

+1

+1 pour utiliser 'Through' dans votre" preuve "=) –

4

Chaque fois que vous voyez quelque chose comme [email protected]@@Transpose[{args}] vous devriez penser à Thread[]. Cela a été discuté dans The semantics of Mathematica's Thread function.

Donc, le mieux que je pouvais faire était

func[l_, g_, f_] := g @@ Thread[f[Most[l], Rest[l]]] 

mais la construction Most[l], Rest[l] semble encore laid et inefficace. Il y a probablement un moyen plus efficace de le faire - mais peut-être est-ce aussi compact qu'il peut l'être dans Mathematica.

+0

Merci de m'avoir signalé "Thread" - bien que j'aime réellement @@@ '. En ce qui concerne le 'Transpose [Most, Rest]' la chose à faire est d'utiliser 'Partition'. – Janus

+1

@Simon Hey! Ne pas copier! : D –

+0

@Janus Partition [l, Longueur @ l - 1, 1] = {La plupart, Repos} –

3

équivalent à (ne dis pas qu'il vaut mieux):

 func[l_, g_, f_] := g @@ Thread[f[[email protected], [email protected]]] 

Ou presque

 func[l_, g_, f_] := g @@ f /@ Partition[l, 2, 1] 

Mais ce dernier besoin

 func[l, Plus, (#[[1]] + #[[2]])^2 &] 

Ce qui est nettement inférieur

2

Je pense que c'est juste un produit intérieur généralisé (produit scalaire généralisé), modulo le bit Transpose/Most/Rest, vous pouvez aussi utiliser Inner:

func[lis_, f_, g_] := Inner[f, [email protected]@Partition[list, Length[lis]-1, 1], g] 

In[90]:= func[l,Plus,(#-#2)^2&] 
Out[90]= (a - b)^2 + (b - c)^2 + (c - d)^2 

Il y a aussi MapThread, que je mentionne pour l'exhaustivité:

func2[lis_, g_, f_] := g @@ MapThread[f, Partition[lis, Length[lis]-1, 1]] 

In[94]:= func2[l, Plus, (# - #2)^2 &] 
Out[94]= (a - b)^2 + (b - c)^2 + (c - d)^2 

Si vous faites toujours des différences hors de la liste, Differences ou ListConvolve pourrait être plus rapide, comme d'autres l'ont mentionné.

Comme Perl, TMTOWTDI dans Mathematica aussi, comme toutes les réponses à votre question montrent!

3

Ceci n'est pas une réponse mais une suggestion pour une meilleure routine de temporisation. Cette

timeAvg[func_] := Module[{ 
    x = 0, y = 0, timeLimit = 0.1, p, q, 
    iterTimes = Power[10, Range[0, 10]]}, 
    Catch[ 
    If[(x = First[Timing[(y++; Do[func, {#}]);]]) > timeLimit, 
     Throw[{x, y}] 
     ] & /@ iterTimes 
    ] /. {p_, q_} :> p/iterTimes[[q]] 
    ]; 
Attributes[timeAvg] = {HoldAll}; 

va calculer un temps d'exécution moyen assez rapidement, par exemple,

[email protected][l, Plus, (#1 - #2)^2 &] 

Essayer différentes longueurs pour l donne le résultat suivant Timing où N est le nombre d'éléments dans l. Thread[] est le gagnant clair.

Questions connexes