Hello and welcome to our community! Is this your first visit?
Register
Enjoy an ad free experience by logging in. Not a member yet? Register.
Results 1 to 1 of 1
  1. #1
    Senior Coder rnd me's Avatar
    Join Date
    Jun 2007
    Location
    Urbana
    Posts
    4,366
    Thanks
    11
    Thanked 590 Times in 571 Posts

    Lightbulb simple list filtering

    intro
    Filtering lists is usually done by hand with some setup involving a valid item collector, a for loop and one or more conditionals.
    That works, but is quite a bit to type out, and i've discovered a very simple way to do so using native javascript statements. I noticed it re-reading the spec last month, and it's already saved me a lot of code writing on a data-centric web server backend, so i thought i'd share the trick here.


    about
    the secret is using the generic potential of RegExp's test() method to filter the results. Since RegExp().test(strData) returns true or false, it's perfect for feeding Array.filter().


    code examples (live demo):
    Code:
    //example text data (from Tom Sawyer) :
    var text="WITHIN a few minutes the news had spread, and a dozen skiff-loads of men were on their way to McDougal's cave, and the ferryboat, well filled with passengers, soon followed. Tom Sawyer was in the skiff that bore Judge Thatcher."
    
    
    //example array: an array with each slot holding one word from above :
    var words=text.split(/[\s,.]+/);
    
    
    alert("All words \n"+ 
    
      words.join("\n")
    );
    
    
    
    
    alert("Words that are 5 or more letters long \n"+ 
    
      words.filter( RegExp().test,  /\w{5,}/ ).join("\n")
    );
    
    
    
    
    alert("Words starting with a vowel \n"+ 
    
      words.filter( RegExp().test,  /^[aeiou]/i ).join("\n")
    );



    boring details:
    A minor technical glitch is that Array.filter separates the method from the context, which means that a .test method on a RegExp instance points to the wrong "this" when executed. That's over-come by using a duck-type compatible this object: the actual RegExp you want to you to test against to set this. Array.filter takes a 2nd argument: this. In short, it takes 2 RegExps to get this to work, but it's still very quick.

    If you make a RegExp ahead of time, you don't have the cool one-liner aspect of the routine anymore, but you can simplify/shorten the call somewhat:

    Code:
    var rx=/e/;
    words.filter( rx.test, tx );

    bonus
    [].filter() and [].map() are powerful, and fast and simple when used with native methods. you may have noticed the empty array slot at the end of words. from the "all words" demo. If that's a problem, filter it out with another native:
    Code:
    var words=text.split(/[\s,.]+/).filter(String);
    Boolean and String are both great [].filter() arguments

    Number is great for strong-typing numerical arrays with map(), or removing non-numbers with filter():

    Code:
    "1,2,3,4,5".split(",").map(Number); //==[1,2,3,4,5]
    "1,a,3,b,5".split(",").filter(Number);//==["1","3","5"]
    "1,a,3,b,5".split(",").filter(Number).map(Number);//==[1,3,5]
    if you need to support older IE versions, you can makes sure [].map is available with code from MDN, use the underscore lib, http://danml.com/f/, or many other libraries.


    here is [].map, [].filter, [].reduce, and all the other "Array 1.6" methods in under 1kb:
    Code:
    eval(function (s,r){var a,x,i=0,m=r.length,q=/([.*+?^${}()|[\]\/\\])/g;for(;i<m;i++){a=r[i]||"";x=RegExp(a.slice(0,1).replace(q,"\\$1"),"g");s=s.replace(x,a.slice(1))}return s}("(&n(#var o=Array.prototype,H,i,e={map/i=0,r=[]BVr[i]8G,V}Nr9J<0Bt@a.3(G,V#r[g++Kt[i]MNr9every/i=0;Nm@t.JU.length==m9some/i=1;Q(;mT;#P@a.3(tDmCm,V@!Ti#$!0}}$!19lastIndexOf/i=b6-1;Q(;m>i;mT#P@t[mK==a#Nl}}$-194dexOf/i=b60Bt@t[iK==a#Ni}}$-19reduce/i=0,r=b6t[i++]L57r8nul*reduceRight/i=m-1,r=b6t[iT]%>-1;iT#r8nul*QEach:&n(a,b#this.concat().mapU9clean<0,x,O;a=Function(a6Str4g)Bt@(x8G,V)#r[g++KxMNarguments[2]?b:rMQ(H 4 e#i=o[H];o[HKi6e[H]}}());","Vt)`U(a,b)`T--`BT4 `TLB `Pif(m 4 t`N$ `M}};`</i=0,r=[Cg=`L%<`K]=`Jfilter`Hit`GbDiCi`D,t[`C],`6||`B576`Qfor`&functio`@&&`9},`8=a.3(`7++#`6if(i`5m;i`4in`3call`#){`/:#,`*l,r,t[i],i,t)}$ r},`%;for(;i`$return`#functio$length`$n(a,b){var t=#=t.`#this.concat(),m".split('`')));
    Last edited by rnd me; 11-10-2011 at 04:51 PM.
    my site (updated 13/9/26)
    BROWSER STATS [% share] (2014/9/03) IE7:0.1, IE8:4.6, IE11:9.1, IE9:3.1, IE10:3.0, FF:17.2, CH:46, SF:11.4, NON-MOUSE:38%

  2. Users who have thanked rnd me for this post:

    Kor (11-21-2011)


 

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •