The extended map function

The map function I will present is the most useful map function you'll find. Why? Because it can replace most for loops! And replacing for loops will produce much cleaner JavaScript code.

What is a map function? Standard map function applies a function to a sequence of elements. Let's do a rewrite that will show you what I mean. A for loop could like this:

var list = [1, 2, 3]
for(var i=0; i < list.length; i++)
   myFn(list[i])

Rewritten using map the above loop will look like this:

map([1, 2, 3], my_fn)

Much cleaner don't you think?

The extensions

Most library's (JQuery, Prototype, MochiKit) implement a dumb map function, that acts as "the real map function", i.e. a map function that can only apply a function to a sequence of elements and nothing more. But I figured out there is no need to put such a limitation. The map function could be almost as powerful as a for loop!

My map function signature looks like this:

map(list, fn, /*optional*/ start_index, end_index)

Notice that you can specify a start_index and end_index, an example:

map(['A', 'm', 'i', 'r'], function(char) {
   alert(char)
}, 1, 3)

The above code will alert 'm', 'i'. The above example looks like this using a standard for loop:

var chars = ['A', 'm', 'i', 'r'];
for(var i=1; i < 3; i++) {
   alert(chars[i])
}

That's the first extension and you may find it quite useful in certain situations.

The second extension is, that you can get the current index, an example:

map(['A', 'm', 'i', 'r'], function(char, i) {
   alert(i + ':' + char);
});

The above example will alert 0:A, 1:m, 2:i, 3:r. This extension is also quite useful in certain situations.

The third extension is, that you can return from a map function - this is really useful. An example:

var is_i_found = map(['A', 'm', 'i', 'r'], function(char) {
   if(char == i)
      return true;
});
alert(is_i_found); //Alerts true

Anyway, the extensions may look like an overkill, but I can assure you that they are quite useful. In Todoist I only use around 6 for loops (and I have around 5000 lines of JavaScript), everything is handled by the extended map function!

The implementation

function map(list, fn,/*optional*/ start_index, end_index) {
    var i = 0, l = list.length;
    if(start_index)
         i = start_index;
    if(end_index)
         l = end_index;
    for(i; i < l; i++) {
        var val = fn.apply(null, [list[i], i]);
        if(val != undefined)
            return val;
    }
}

That's it. You'll find this map function in AJS (my JavaScript library).

A real world example

In Todoist it's possible to write a every last day recurring event. In order to implement this, one needs to know the last day of a month. Here is how I solve this using the extended map function:

function getLastDay(_date) {
    var clone = new Date(_date);
    var now_month = _date.getMonth();
    return map([31, 30, 29, 28], function(days) {
        now = new Date(clone);
        now.setDate(days);
        if(now_month == now.getMonth())
            return now;
    });
}

The above code takes a date as input and returns a new "last day" date object. Notice the usage of map.

Code · JavaScript · Tips 26. Apr 2007
7 comments so far

looks nice, but if I can offer some thing:

function map(list, fn,/*optional*/ sindex, eindex, bind)
{
    var i = sindex || 0;
    var l = eindex && eindex <= list.length ? eindex;

    for(i; i < l; i++)
    {
        var res = fn.call(bind, list[i], i);
        if (res != undefined && res != null)
            return res;
    }
}

b.s. in the 6th exaple code :

var is_i_found = function(['A', 'm', 'i', 'r'], ....

I believe here function have to be map ;)

Sorry, I don't like it. Indexing does not belong in a map function. Indexing and slicing are operations of the sequence, as they should be. Likewise for the function of enumerating an index over an iterable. Separation of concerns is cleaner. Taking python as an example, you demonstration would be written:

map(lambda (i, c): alert(':'.join(i, c)), enumerate("Amir"[1:3]))

Also:

[1, 2, 3, 4].map(function(el){ return el*2; }); // [2, 4, 6, 8]

[1, 2, 3, 4].map('el*2'); // [2, 4, 6, 8]

// 
Array.prototype.map = function(callback, thisObject)
{
  if (typeof callback == 'string') callback = new Function('el', 'i', 'array', 'return ' + callback);
  var array = [];
  for (var i = 0, len = this.length; i < len; ++i)
    array.push(callback.call(thisObject, this[i], i, this));
  return array;
}

RStankov:
One can do following (instead of having bind as a parameter):

map([1, 2, 3], bind(fn, scope));

Calvin:
This is a JavaScript "hack" and comparing it to Python is a bit unfair :) But I would say that map with index capability is much cleaner than a for loop.

Thank you

Thank you very much for this information. I like this site

عقارات السعودية - عقارات الرياض - عقارات الخرج - عقارات مكة المكرمة - عقارات جدة - عقارات الطائف - عقارات المدينة المنورة - عقارات ينبع - عقارات الدمام - عقارات الخبر - عقارات الأحساء - عقارات القصيم - عقارات عسير - عقارات حائل - عقارات تبوك - عقارات الباحة - عقارات الحدود الشمالية - عقارات الجوف - عقارات جازان - عقارات نجران - عقارات مصر - عقارات القاهرة - عقارات الجيزة - عقارات حلوان - عقارات 6 اكتوبر - عقارات الاسكندرية - عقارات الساحل الشمالي - عقارات البحيرة - عقارات السويس - عقارات الاسماعلية - عقارات بورسعيد - عقارات البحر الاحمر - عقارات مطروح - عقارات جنوب سيناء - عقارات شمال سيناء - عقارات دمياط - عقارات الدقهلية - عقارات كفر الشيخ - عقارات الشرقية - عقارات الغربية - عقارات القليوبية - عقارات المنوفبة - عقارات الفيوم - عقارات قنا - عقارات المنيا - عقارات اسيوط - عقارات بني سويف - عقارات سوهاج - عقارات الوادي الجديد - عقارات الأقصر - عقارات اسوان - عقارات الامارات - عقارات ابوظبي - عقارات العين - عقارات دبي - عقارات جبل علي - عقارات الشارقة - عقارات رأس الخيمة - عقارات عجمان - عقارات أم القيوين - عقارات الفجيرة - الوطن العربي - عقارات الكويت - عقارات عمان - عقارات قطر - عقارات البحرين - عقارات الاردن - عقارات لبنان - عقارات المغرب - عقارات السودان - عقارات سوريا - وظائف - وظائف في السعودية - وظائف في الامارات - وظائف في مصر - وظائف في الكويت - وظائف في عمان - وظائف في قطر - وظائف في البحرين - وظائف في الاردن - وظائف في لبنان - وظائف في المغرب - وظائف في السودان - وظائف في سوريا - خدمات - العروض الجديدة - الرعاية و الإعلان - الدعم الفني - العقارات العام - شراء شقق - شراء شقة - شقق بالتقسيط - شقة بالتقسيط - شقق تمليك - شقة تمليك - شقق سكنية - شقة سكنية - شقق فندقية - شقة فندقية - شقق للايجار - شقة للايجار - شقق للبيع - شقة للبيع - شقق مفروشة - شقة مفروشة - غير مصنف - مطلوب شقق - مطلوب شقة
اهداف الدوري الأنجليزي
اهداف الدوري الأسباني
اهداف دوري ابطال اوروبا
مهارات ولقطات منوعة
اهداف الدوري السعودي
اهداف تصفيات كأس العالم
اهداف الدوري المصري
اهداف الدوري الالماني
أهداف كأس الخليج
هدف تيوب

Post a comment
Commenting on this post has expired.
© 2000-2009 amix. Powered by Skeletonz.