Molti algoritmi (come l'algoritmo per trovare la successiva permutazione di un elenco in ordine lessicografico) implicano la ricerca dell'indice dell'ultimo elemento in un elenco. Tuttavia, non sono stato in grado di trovare un modo per farlo in Mathematica che non sia imbarazzante. L'approccio più diretto utilizza LengthWhile
, ma significa invertire l'intera lista, che rischia di essere inefficiente nei casi in cui si conosce l'elemento che si desidera è vicino alla fine della lista e invertire il senso del predicato:Ricerca dalla fine di un elenco in Mathematica
findLastLengthWhile[list_, predicate_] :=
([email protected] - LengthWhile[[email protected], ! [email protected]# &]) /. (0 -> $Failed)
Potremmo fare un ciclo esplicito, imperativo con Do
, ma anche questo risulta un po 'goffo. Sarebbe utile se Return
sarebbe in realtà tornare da una funzione al posto del blocco Do
, ma non è così, così si potrebbe anche utilizzare Break
:
findLastDo[list_, pred_] :=
Module[{k, result = $Failed},
Do[
If[[email protected][[k]], result = k; Break[]],
{k, [email protected], 1, -1}];
result]
In ultima analisi, ho deciso di iterare utilizzando coda ricorsione, che significa che la terminazione anticipata è un po 'più facile. Utilizzando il strano ma utile #0
notazione che consente funzioni anonime fanno chiamare, questo diventa:
findLastRecursive[list_, pred_] :=
With[{
step =
Which[
#1 == 0, $Failed,
[email protected][[#1]], #1,
True, #0[#1 - 1]] &},
step[[email protected]]]
Tutto questo sembra troppo difficile, però. Qualcuno vede un modo migliore?
MODIFICA aggiungere: Naturalmente, la mia soluzione preferita ha un bug che significa che è rotto su lunghi elenchi a causa di $IterationLimit
.
In[107]:= findLastRecursive[Range[10000], # > 10000 &]
$IterationLimit::itlim: Iteration limit of 4096 exceeded.
Out[107]= (* gack omitted *)
È possibile risolvere questo problema con Block
:
findLastRecursive[list_, pred_] :=
Block[{$IterationLimit = Infinity},
With[{
step =
Which[
#1 == 0, $Failed,
[email protected][[#1]], #1,
True, #0[#1 - 1]] &},
step[[email protected]]]]
$IterationLimit
non è la mia caratteristica preferita Mathematica.
Se solo le liste erano rappresentate come strutture a collegamento doppio ... –
sei sicuro che la prima riga di codice sia corretta? A meno che non capisco cosa dovrebbe fare, il secondo 'LengthWhile 'non dovrebbe essere' LengthWhile [list // Reverse, predicate @ # &] '? Quindi, aggiungendo un 'Reverse' e rimuovendo'! '? –
@Sjoerd C. de Vries Sì, hai ragione. Ho modificato in una correzione. – Pillsy