Сделать Javascript сделать понимание списка - PullRequest
57 голосов
/ 11 февраля 2011

Какой самый чистый способ заставить Javascript сделать что-то как понимание списка Python?

В Python, если у меня есть список объектов, имена которых я хочу «вытащить», я бысделать это ...

list_of_names = [x.name for x in list_of_objects]

В javascript я не вижу более «красивого» способа сделать это, кроме как просто использовать конструкцию цикла for.

К вашему сведению: I 'используя jQuery;может быть, у него есть какая-то изящная особенность, которая делает это возможным?

В частности, скажем, я использую селектор jQuery, такой как $('input'), чтобы получить все input элементы, как бы я наиболее чисто создал массив всех атрибутов name для каждогоиз этих input элементов, т. е. всех $('input').attr('name') строк в массиве?

Ответы [ 10 ]

50 голосов
/ 11 февраля 2011

универсальный случай с использованием Array.map , требует javascript 1.6 (это означает, что работает в любом браузере, но IE <9) <em>или с инфраструктурой дополнения объектов, такой как MooTools, работает в любом браузере :

var list_of_names = document.getElementsByTagName('input').map(
  function(element) { return element.getAttribute('name'); }
);

jQuery конкретный пример, работает на любом браузере:

var list_of_names = jQuery.map(jQuery('input'), function(element) { return jQuery(element).attr('name'); });

другие ответы, использующие .each, неверны; не сам код, но реализации являются неоптимальными.

Редактировать: есть также Массивы , представленные в Javascript 1.7, но это чисто зависит от синтаксиса и не может быть эмулировано в браузерах, в которых он отсутствует. Это самая близкая вещь, которую вы можете получить в Javascript к фрагменту Python, который вы опубликовали.

11 голосов
/ 31 августа 2013

Понимание списка состоит из нескольких частей.

  1. Выбор набора чего-либо
  2. Из набора чего-то
  3. Filtered by Something

В JavaScript, начиная с ES5 (так что я думаю, что это поддерживается в IE9 +, Chrome и FF), вы можете использовать функции map и filter для массива.

Вы можете сделатьэто с картой и фильтром:

var list = [1,2,3,4,5].filter(function(x){ return x < 4; })
               .map(function(x) { return 'foo ' + x; });

console.log(list); //["foo 1", "foo 2", "foo 3"]

Это примерно так же хорошо, как и без установки дополнительных методов или использования другой платформы.

Что касается конкретного вопроса ...

С jQuery:

$('input').map(function(i, x) { return x.name; });

Без jQuery:

var inputs = [].slice.call(document.getElementsByTagName('input'), 0),
    names = inputs.map(function(x) { return x.name; });

[].slice.call() isпросто чтобы преобразовать NodeList в Array.

6 голосов
/ 18 июля 2012

Те, кто интересуется "красивым" Javascript, вероятно, должны проверить CoffeeScript , язык, который компилируется в Javascript. По сути, он существует, потому что в Javascript отсутствуют такие вещи, как понимание списка.

В частности, понимание списка Coffeescript еще более гибкое, чем у Python. См. список документов для понимания здесь .

Например, этот код приведет к массиву name атрибутов input элементов.

[$(inp).attr('name') for inp in $('input')]

Однако потенциальным недостатком является то, что полученный Javascript многословен (и ИМХО сбивает с толку):

var inp;
[
  (function() {
    var _i, _len, _ref, _results;
    _ref = $('input');
    _results = [];
    for (_i = 0, _len = _ref.length; _i < _len; _i++) {
      inp = _ref[_i];
      _results.push($(inp).attr('name'));
    }
    return _results;
  })()
];
4 голосов
/ 11 февраля 2011

Итак, понимание списка в python фактически делает две вещи одновременно: отображение и фильтрацию.Например:

list_of_names = [x.name for x in list_of_object if x.enabled]

Если вы просто хотите отобразить часть, как показано в вашем примере, вы можете использовать функцию карты jQuery.Если вам также нужна фильтрация, вы можете использовать функцию "grep" в jQuery.

2 голосов
/ 18 января 2014

Массивы являются частью проекта ECMAScript 6. В настоящее время (январь 2014 г.) только JavaScript в Mozilla / Firefox реализует их.

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]

Хотя ECMAScript 6 недавно переключился на синтаксис слева направо, аналогичный C # и F #:

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

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

2 голосов
/ 11 февраля 2011

Повторно используемый способ сделать это - создать крошечный плагин jQuery, подобный этому:

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

Тогда вы можете использовать его следующим образом:

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

Это не списокпонимание, но это не существует в JavaScript.Все, что вы можете сделать, это использовать javascript и jquery для того, для чего это хорошо.

1 голос
/ 25 сентября 2014

Это пример места, где Coffeescript действительно сияет

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

Эквивалентный Javascript будет:

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;
  })()
];
1 голос
/ 25 сентября 2013

Существует однострочный подход, включающий использование вложенной функции закрытия в конструктор списка. И функция, которая работает долго, чтобы генерировать последовательность. Это определено ниже:

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]

Это реализация, основанная на диапазоне, например диапазон Python (min, max) Кроме того, понимание списка следует этой форме:

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

некоторые тесты:

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]

Хотя это решение не самое чистое, оно выполняет свою работу. И в производстве я бы, вероятно, советовал против этого.

Наконец, можно выбрать не использовать рекурсию для моего метода «генерирования», так как это сделает работу быстрее. Или даже лучше использовать встроенную функцию из многих популярных библиотек Javascript. Вот перегруженная реализация, которая также приспособилась бы для свойств объекта

// 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]);
};

Использование:

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; }))];

Синтаксис отстой, я знаю!

Удачи.

1 голос
/ 17 января 2012

Да, я тоже скучаю по спискам.

Вот ответ, который немного менее многословен, чем ответ @ gonchuki, и преобразует его в фактический массив вместо типа объекта.

var list_of_names = $('input').map(function() {
    return $(this).attr('name');
}).toArray();

В этом случае используются все отмеченные флажки и их объединение в хеш URL, например:

window.location.hash = $('input:checked').map(function() {
    return $(this).attr('id');
}).toArray().join(',');
0 голосов
/ 11 февраля 2011

Используя функцию jQuery .each(), вы можете перебирать каждый элемент, получать индекс текущего элемента и, используя этот индекс, вы можете добавить атрибут name в массив list_of_names ...

var list_of_names = new Array();

$('input').each(function(index){
  list_of_names[index] = $(this).attr('name');
});

Хотя это, по сути, метод зацикливания, который, как вы указали, вам не нужен, он представляет собой невероятно аккуратную реализацию зацикливания и позволяет запускать цикл для определенных селекторов.

Надеюсь, что это поможет:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...