Make Javascript do List Comprehension

后端 未结 10 1147
情话喂你
情话喂你 2020-12-05 09:05

What is the cleanest way to make Javascript do something like Python\'s list comprehension?

In Python if I have a list of objects whose name\'s I want to \'

相关标签:
10条回答
  • 2020-12-05 09:57

    There is a one line approach, it involves using a nested closure function in the constructor of the list. And a function that goes a long with it to generate the sequence. Its defined below:

    var __ = generate = function(initial, max, list, comparision) {
      if (comparision(initial))
        list.push(initial);
      return (initial += 1) == max + 1 ? list : __(initial, max, list, comparision);
    };
    
    [(function(l){ return l; })(__(0, 30, [], function(x) { return x > 10; }))];
    // returns Array[20]
    var val = 16;
    [(function(l){ return l; })(__(0, 30, [], function(x) { return x % val == 4; }))];
    // returns Array[2]
    

    This is a range based implementation like Python's range(min, max) In addition the list comprehension follows this form:

    [{closure function}({generator function})];
    

    some tests:

    var alist = [(function(l){ return l; })(__(0, 30, [], function(x) { return x > 10; }))];
    var alist2 = [(function(l){ return l; })(__(0, 1000, [], function(x) { return x > 10; }))];
    // returns Array[990]
    var alist3 = [(function(l){ return l; })(__(40, 1000, [], function(x) { return x > 10; }))];
    var threshold = 30*2;
    var alist3 = [(function(l){ return l; })(__(0, 65, [], function(x) { return x > threshold; }))];
    // returns Array[5]
    

    While this solution is not the cleanest it gets the job done. And in production i'd probably advise against it.

    Lastly one can choose not to use recursion for my "generate" method as it would do the job quicker. Or even better use a built in function from of the many popular Javascript libraries. Here is an overloaded implementation that would also accommodate for object properties

    // A list generator overload implementation for
    // objects and ranges based on the arity of the function.
    // For example [(function(l){ return l; })(__(0, 30, [], function(x) { return x > 10; }))] 
    // will use the first implementation, while
    // [(function(l){ return l; })(__(objects, 'name', [], function(x, y) { var x = x || {}; return x[y] }))];
    // will use the second.
    
    var __ = generator = function(options) {
      return arguments.length == 4 ?
    // A range based implemention, modeled after pythons range(0, 100)
      (function (initial, max, list, comparision) {
        var initial = arguments[0], max = arguments[1], list = arguments[2], comparision = arguments[3];
        if (comparision(initial))
          list.push(initial);
        return (initial += 1) == max + 1 ? list : __(initial, max, list, comparision);
      })(arguments[0], arguments[1], arguments[2], arguments[3]):
    // An object based based implementation. 
      (function (object, key, list, check, acc) {
        var object = arguments[0], key = arguments[1], list = arguments[2], check = arguments[3], acc = arguments[4];
        acc = acc || 0;
        if (check(object[acc], key))
          list.push(object[acc][key]);
        return (acc += 1) == list.length + 1 ? list : __(object, key, list, check, acc); 
      })(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4]);
    };
    

    Usage:

    var threshold = 10;
    [(function(l){ return l; })(__(0, 65, [], function(x) { return x > threshold; }))];
    // returns Array[5] -> 60, 61, 62, 63, 64, 65
    var objects = [{'name': 'joe'}, {'name': 'jack'}];
    [(function(l){ return l; })(__(objects, 'name', [], function(x, y) { var x = x || {}; return x[y] }))];
    // returns Array[1] -> ['Joe', 'Jack']
    [(function(l){ return l; })(__(0, 300, [], function(x) { return x > 10; }))];
    

    The syntax sucks I know!

    Best of luck.

    0 讨论(0)
  • 2020-12-05 09:59

    Added by @yurik: Do not use. Array comprehensions were proposed but later removed.

    Array comprehensions are a part of the ECMAScript 6 draft. Currently (January 2014) only Mozilla/Firefox's JavaScript implements them.

    var numbers = [1,2,3,4];
    var squares = [i*i for (i of numbers)]; // => [1,4,9,16]
    var somesquares = [i*i for (i of numbers) if (i > 2)]; // => [9,16]
    

    Though ECMAScript 6 recently switched to left-to-right syntax, similar to C# and F#:

    var squares = [for (i of numbers) i*i]; // => [1,4,9,16]
    

    http://kangax.github.io/es5-compat-table/es6/#Array_comprehensions

    0 讨论(0)
  • A re-usable way of doing this is to create a tiny jQuery plugin like this:

    jQuery.fn.getArrayOfNames = function() {
        var arr = [];
        this.each( function() { arr.push(this.name || ''); } );
        return arr;
    };
    

    Then you could use it like this:

    var list_of_names = $('input').getArrayOfNames();
    

    It's not list comprehension, but that doesn't exist in javascript. All you can do is use javascript and jquery for what it's good for.

    0 讨论(0)
  • 2020-12-05 10:06

    This is an example of a place where Coffeescript really shines

    pows = [x**2 for x in foo_arr]
    list_of_names = [x.name for x in list_of_objects]
    

    The equivalent Javascript would be:

    var list_of_names, pows, x;
    
    pows = [
      (function() {
        var _i, _len, _results;
        _results = [];
        for (_i = 0, _len = foo_arr.length; _i < _len; _i++) {
          x = foo_arr[_i];
          _results.push(Math.pow(x, 2));
        }
        return _results;
      })()
    ];
    
    list_of_names = [
      (function() {
        var _i, _len, _results;
        _results = [];
        for (_i = 0, _len = list_of_objects.length; _i < _len; _i++) {
          x = list_of_objects[_i];
          _results.push(x.name);
        }
        return _results;
      })()
    ];
    
    0 讨论(0)
提交回复
热议问题