2012-01-16 8 views
10

Muszę użyć If wewnątrz pętli Table, np. Table[If[i< 3, i], {i, 5}] da {1, 2, Null, Null, Null}Jak usunąć symbol zerowy w tabeli w języku Mathematica?

Ale chcę, aby wynik był {1,2}.

Jakieś rozwiązanie tego problemu?

EDIT:
Co jeśli weźmiemy pod uwagę Table[If[i< 3, f[i]], {i, 5}] co daje {f[1], f[2], Null, Null, Null}

+0

Nieco pokrewne pytanie: http://stackoverflow.com/q/ 6313505/618728 –

+0

Powiązane pytanie: http://mathematica.stackexchange.com/questions/3700/how-to-avoid-returning-a-null-if-there-is-no-else-condition-in-an-if -contruct – anderstood

Odpowiedz

27

zwięźle:

Table[If[i < 3, i, ## &[]], {i, 5}] 

Działa to, ponieważ funkcja ## & nie podlega natychmiastowej ocenie.

## & to funkcja "znikająca".

{1, 2, ## &[], 3, 4} 
----> {1, 2, 3, 4} 

Zobacz SlotSequence aby uzyskać więcej informacji.

+5

+1 za przypomnienie wszystkim o '## & []'. –

+1

@Leonid dzięki za pokazanie lub przypomnienie mi o tym kilka miesięcy temu. –

+3

Myślę, że to był twój wynalazek. Zwykle używam 'Sequence @@ {}', która nie jest tak elegancka (i może być odrobinę wolniejsza). –

14

Jeżeli trzeba go usunąć z istniejącej listy, można użyć

DeleteCases[list, Null] 

lub

list /. Null -> Sequence[] 

(nieco bardziej zaawansowany).


dotycząceTwojego przykład Table powyżej pierwszej nuty, że drugi przecinek w If jest konieczne (a nawet będzie podświetlone na różowo):

list = Table[If[i < 3, i], {i, 5}] 

do filtrowania elementów tabeli przez warunek, to polubisz zamiast tego chcesz użyć czegoś podobnego do podobnego do tego, co podobnego do

list = Select[Table[i, {i, 5}], # < 3 &] 

.


Wreszcie, jeśli trzeba wygenerować listę bez kiedykolwiek dodawanie elementów odrzuconych do niego (aby zaoszczędzić pamięć), proponuję przy użyciu Reap i Sow:

[email protected][If[i < 3, Sow[i]], {i, 5}] 
list = %[[2, 1]] 

nie zostały faktycznie zweryfikowane wykorzystanie pamięci tego w porównaniu do zwykłego Table, i zauważ, że jeśli generujesz tylko liczby, które mogą być przechowywane w packed array, konstrukcja Table może być bardziej wydajna pod względem pamięci. Z drugiej strony, jeśli wygenerujesz naprawdę ogromną liczbę ogólnych wyrażeń, z których większość zostanie odrzucona w If, Sow/może być lepsza.

+0

+1. Faktycznie zaimplementowałem twoją ostatnią sugestię z 'Reap-Sow' w pełnej ogólności w odpowiedzi, do której się przyłączyłem, w mojej odpowiedzi (może być tylko składnia warunku może być bardziej przyjazna). –

6

Alternatywnie można użyć wersji Table z this answer, która została zaprojektowana specjalnie do warunkowego tworzenia tabel. Oto, jak będzie wyglądał:

In[12]:= tableGenAltMD[i,{i,5},#<3&] 
Out[12]= {1,2} 

Ostatni argument jest funkcją reprezentującą warunek. Właściwie byłoby dobrze mieć również składnię, w której można by bezpośrednio użyć i (i/lub innych zmiennych iteracyjnych) i taka składnia prawdopodobnie nie jest trudna do dodania.

+0

Proszę rozważyć zilustrowanie, dlaczego może to być preferowane w stosunku do uproszczonej odpowiedzi, którą podałem poniżej. –

+1

@Mr. Kreator Z bardzo prostego powodu: jest to funkcja ogólna (moja wersja). Obsługuje również wielowymiarowy przypadek z jednolitą składnią. Wciąż jest łatwiej czytać i byłoby jeszcze łatwiej, gdy dodałem składnię, aby zastąpić funkcję wyrażeniem warunku. Gdyby to była funkcja wbudowana lub po prostu zatwierdzona przez WRI, nie byłoby mowy o używaniu czegokolwiek innego. Wyobraź sobie, że nie powiedziałbyś "Sprawy", a ktoś ci to daje (zaimplementowany na najwyższym poziomie). Nie używałbyś tego (jeśli wdrożenie jest w porządku)? Wiele z nich dotyczy właśnie nawyków, konwencji itp. –

+0

Być może powinieneś uwzględnić to w swojej odpowiedzi? ;-) –

3

Jeśli używasz Sequence [] zamiast NULL, wtedy można zrobić

Table[If[i < 3, i, Hold[Sequence[]]] // ReleaseHold, {i, 5}] 

chciałem od dawna, że ​​jeśli miały atrybut SequenceHold. Myślę, że kiedyś zaproponowałem to WRI, ale są prawdopodobnie (dobre?) Powody, dla których nie należy przypisywać tego atrybutu . Można spróbować, jeśli ktoś odważy się zmienić wbudowanych symboli (które należy prawdopodobnie nie zrobić):

Unprotect[If]; 
SetAttributes[If, SequenceHold]; 

Następnie Sequence [], jeśli będzie tylko działać:

Table[If[i < 3, i, Sequence[]], {i, 5}] 
+0

Rolf, zobacz odpowiedź, którą właśnie dodałem. Prawie zredagowałem twoje pytanie zamiast go opublikować, ale zdałem sobie sprawę, że zasadniczo zastąpię twoją odpowiedź moją, więc nie. –

+0

Mr. Wizard: bardzo miło! Nie wiedziałem, że ## & @ [] jest odpowiednikiem sekwencji []. –

1

W poprzednim anwser, część ## &[] może być zastąpiony przez wbudowany symbol Nothing

Table[If[i < 3, i, Nothing], {i, 5}] 

daje

{1, 2}