filter(E)

FUNKTION:
     mixed * filter (mixed *arg, string fun, string|object ob
                                              , mixed extra...)
     mixed * filter (mixed *arg, closure cl, mixed extra...)
     mixed * filter (mixed *arg, mapping map, mixed extra...)

     string  filter (string arg, string fun, string|object ob
                                        , mixed extra...)
     string  filter (string arg, closure cl, mixed extra...)
     string  filter (string arg, mapping map, mixed extra...)

     mapping filter (mapping arg, string func, string|object ob
                                             , mixed extra...)
     mapping filter (mapping arg, closure cl, mixed extra...)

PARAMETER:
     arr     - zu filterndes Array/Mapping/String
     fun/cl  - zu rufende Methode/Closure
     map     - filterndes Mapping
     ob      - Objekt/Dateiname, an dem Methode gerufen werden soll
     extra   - weitere Parameter fuer Methode/Closure

BESCHREIBUNG:        
     Ruft fuer jedes Element des Arrays oder Mappings <arg> die Funktion
     <ob>-><func>() bzw. die Closure <cl> auf und liefert jene Elemente,
     fuer die die Funktion / Closure TRUE ergeben hat. Die <extra>
     Argumente werden als zusaetzliche Parameter an die Funktion
     uebergeben und duerfen keine Referenzen von Array- oder Mapping-
     Elementen sein (wie &(i[1]) ).

     Wird <ob> nicht angegeben oder ist es weder ein String noch ein
     Objekt, wird standardmaessig this_object() verwendet.

     Ist <arg> ein Array, wird <fun> mit jedem Element des Arrays als
     ersten Parameter aufgerufen, gefolgt von den <extra> Argumenten.
     Wenn das Resultat der Funktion TRUE ergibt, wird das Element in das
     Ergebnis der filter() Operation mit einbezogen.

     Wird filter() mit einem Mapping <map> anstelle der Funktion <func>
     aufgerufen, wird jedes Element im Array <arg>, das ein Key von <map>
     ist, ins Ergebnis mit einbezogen.

     Wenn <arg> ein Mapping ist, wird die Funktion <func> mit jedem Key
     als erstem und (falls vorhanden) den Werten dieses Keys als restliche
     Parameter, gefolgt von den <extra> Argumenten, aufgerufen. Wenn die
     Funktion TRUE ergibt, wird das betreffende Element des Mappings ins
     Ergebnis aufgenommen.

     Abhaengig von der Groesse des Mappings <arg> erfolgt der Aufruf der
     Funktion auf drei unterschiedliche Arten:

     widthof(arg) == 0:  ob->func(key, 0, extra,...);
     widthof(arg) == 1:  ob->func(key, arg[key], extra, ...);
     widthof(arg) >1:    ob->fund(key, ({arg[key,0]...arg[key, n-1]}),
                                  extra, ...);

     Der Vorteil dieser Vorgehensweise ist, dass beide Typen von
     multidimensionalen Mappings (Mappings mit mehreren Werte pro Key und
     Mappings aus Arrays) gleich verarbeitet werden koennen.

     Ist <arg> ein String, werden der Filterfunktion die einzelnen Zeichen des
     Strings uebergeben und nur jene Zeichen im zurueckgegebenen String
     aufgenommen, fuer die die Filterfunkton != 0 zurueckgibt.

AENDERUNGEN
     Eingefuehrt in LDMud 3.2.6. Die Funktion loest filter_array() ab.

RUeCKGABEWERT:
     Gefiltertes Array mit allen die Filterbedingung erfuellenden Elementen.

BEMERKUNGEN:
     (1) Achtung, die Elemente in 'arr' werden nicht tief kopiert, sind sie
     also selbst Arrays oder Mappings, so fuehrt eine spaetere Aenderung im
     Rueckgabe-Arrays zur Aenderung im Ursprungsarray:

     int *i, *j;
     i=({({1,2,3}),({4,5,6})});
     j=filter(i, #'sizeof);     // filtert leere Arrays heraus
     j[0][0]=8;

     fuehrt zu: i==j==({({8,2,3}),({4,5,6})});

     (2) Das Kopieren in das Rueckgabemapping erfolgt fuer jedes Element nach
     Ausfuehrung der Filtermethode. Aenderungen der Werte im Array in dieser
     Methode (globale Variable/Uebergabe als Referenz an filter)
     schlagen sich also im Rueckgabearray nieder.

     (3) Fuer Arrays wirkt filter() wie filter_array(), fuer Mappings stellt
     filter() eine Verallgemeinerung von filter_indices() dar.

BEISPIEL:
     ### Filtere alle Lebewesen in einem Raum in ein Array ###
     filter(all_inventory(this_object()),#'living);


     ### Filtere alle tauben Spieler im Raum in ein Array ###
     static int filter_isdeaf(object who) {
       return (interactive(who) && who->QueryProp(P_DEAF));
     }
     
     filter(all_inventory(this_object()), #'filter_isdeaf);


     ### Filtern von Idlern (>=1 Sekunde idle) ###
     // Folgend identische Resultate, aber andere Ansaetze:

     #1: nutzt die Efun query_idle() als Lfun-Closure (ideal hier)
         idle_usr = filter(users(), #'query_idle );

     #2: mit Filtermethode
         int check_if_idle(object user) {
           return query_idle(user);
         }
         
         #2a: filtert mittels der Lfun im selben Objekt die Idler in das
              Rueckgabearray
              idle_usr = filter(users(), "check_if_idle");
              idle_usr = filter(users(), "check_if_idle", this_object());

         #2b: ruft die Lfun check_if_idle() als Lfun-Closure (Funktions-
              pointer)
              idle_usr = filter(users(), #'check_if_idle );

     #3: nutzt eine Lambda-Closure (langsamer, nicht fuer alle leserlich)
         idle_usr = filter(users(), lambda(({'u}), ({#'query_idle, 'u})));

     #4: erreicht dasselbe wie #3 mit besser lesbarer Inline-Closure
         idle_usr = filter(users(), function int (object user) {
                      return query_idle(user);
                    } );

     ### Filtern von Idlern (>=20 Sekunden idle) mit Extraparameter ###
     // Folgend identische Resultate, aber andere Ansaetze:

     #1: die Efun koennen wir nicht mehr direkt nutzen, weil sie
         diesen Parameter nicht unterstuetzt
        // idle_usr = filter(users(), #'query_idle );

     #2: mit separater Filtermethode ... mit neuem Parameter
         int check_if_idle(object user, int length) {
           return query_idle(user)>length;
         }
      
         #2a: filtert mittels der Lfun im selben Objekt die Idler in das
              Rueckgabearray ... mit drittem Parameter!
              idle_usr = filter(users(), "check_if_idle", this_object(), 20);

         #2b: ruft die Lfun check_if_idle() als Lfun-Closure (Funktions-
              pointer)
              idle_usr = filter(users(), #'check_if_idle, 20);

     #3: nutzt eine Lambda-Closure (langsamer, nicht fuer alle leserlich)
         idle_usr = filter(users(), 
                      lambda(({'u, 'l}), ({#'>,({#'query_idle, 'u}),'l})), 
                      20);

     #4: erreicht dasselbe wie #3 mit einer deutlich besser lesbaren
         Inline-Closure (gegenueber Lambdas zu empfehlende Variante):
         idle_usr = filter(users(), function int (object user, int length) {
                      return (query_idle(user) > length); 
                      }, 20);


AeQUIVALENZCODE (nicht empfohlen, nur zum Verstaendnis!):
     int i;
     mixed *ret; mixed *input;

     ret=allocate(0);
     i=sizeof(input);
     while(i--)
       if(ob->fun(input[i] [, extra1, extra2, ...]))
       // if(funcall(cl, input[i] [, extra1, extra2, ...]))
       // if(member(map, input[i]))
         ret+=({input[i]});

SIEHE AUCH:
     Arrays:        map(E)
     Objektarrays:  filter_objects(E), map_objects(E)
     Mappings:      filter_indices(E), map_indices(E)
                    walk_mapping(E), member(E)

     Sonstiges:     sort_array(E), unique_array()
                    transpose_array(E)

----------------------------------------------------------------------------
09.04.2008, Zesstra

