Python 让 Javascript 做列表理解

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4964456/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 18:22:39  来源:igfitidea点击:

Make Javascript do List Comprehension

javascriptjquerypythonlist-comprehension

提问by Chris W.

What is the cleanest way to make Javascript do something likePython's list comprehension?

使 Javascript 执行类似于Python 的列表理解的最简洁方法是什么?

In Python if I have a list of objects whose name's I want to 'pull out' I would do this...

在 Python 中,如果我有一个对象列表,其名称是我想“拉出”的,我会这样做......

list_of_names = [x.name for x in list_of_objects]

In javascript I don't really see a more 'beautiful' way of doing that other than just using a for loop construct.

在 javascript 中,除了仅使用 for 循环构造之外,我真的没有看到更“漂亮”的方式来做到这一点。

FYI: I'm using jQuery; maybe it has some nifty feature that makes this possible?

仅供参考:我正在使用 jQuery;也许它有一些漂亮的功能使这成为可能?

More specifically, say I use a jQuery selector like $('input')to get all inputelements, how would I most cleanlycreate an array of all the nameattributes for each of these inputelements--i.e., all of the $('input').attr('name')strings in an array?

更具体地说,假设我使用 jQuery 选择器$('input')来获取所有input元素,我将如何最干净地name为每个input元素创建一个包含所有属性的数组- 即数组中的所有$('input').attr('name')字符串?

采纳答案by gonchuki

generic case using Array.map, requires javascript 1.6 (that means, works on every browser but IE < 9) orwith an object augmenting framework like MooTools works on every browser:

使用Array.map 的一般情况,需要 javascript 1.6(这意味着,适用于每个浏览器,但 IE < 9)像 MooTools 这样的对象增强框架适用于每个浏览器:

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

jQuery specific example, works on every browser:

jQuery 特定示例,适用于所有浏览器:

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

the other answers using .eachare wrong; not the code itself, but the implementations are sub-optimal.

使用的其他答案.each是错误的;不是代码本身,而是实现是次优的。

Edit:there's also Array comprehensionsintroduced in Javascript 1.7, but this is purely dependant on syntax and cannot be emulated on browsers that lack it natively. This is the closest thing you can get in Javascript to the Python snippet you posted.

编辑:在 Javascript 1.7 中也引入了数组推导式,但这完全依赖于语法,不能在原生缺少它的浏览器上模拟。这是您在 Javascript 中可以获得的与您发布的 Python 代码段最接近的内容。

回答by Damien-Wright

Using jQuery .each()function, you can loop through each element, get the index of the current element and using that index, you can add the name attribute to the list_of_namesarray...

使用 jQuery.each()函数,您可以遍历每个元素,获取当前元素的索引并使用该索引,您可以将 name 属性添加到list_of_names数组...

var list_of_names = new Array();

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

While this is essentially a looping method, which you specified you did not want, it is an incredibly neat implementation of looping and allows you to run the loop on specific selectors.

虽然这本质上是一种循环方法,您指定了您不想要的方法,但它是一种非常简洁的循环实现,并允许您在特定选择器上运行循环。

Hope that helps :)

希望有帮助:)

回答by typeof

A re-usable way of doing this is to create a tiny jQuery plugin like this:

一种可重用的方法是创建一个像这样的小型 jQuery 插件:

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.

这不是列表理解,但在 javascript 中不存在。你所能做的就是使用 javascript 和 jquery 来做它的好处。

回答by jpsimons

So, python's list comprehensions actually do two things at once: mapping and filtering. For example:

所以,python 的列表推导式实际上同时做两件事:映射和过滤。例如:

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

If you just want the mapping part, as your example shows, you can use jQuery's map feature. If you also need filtering you can use jQuery's "grep" feature.

如果您只需要映射部分,如您的示例所示,您可以使用 jQuery 的地图功能。如果您还需要过滤,您可以使用 jQuery 的“grep”功能。

回答by jedmao

Yeah—I miss list comprehensions too.

是的 - 我也想念列表推导式。

Here's an answer that's slightly less verbose than @gonchuki's answer and converts it into an actual array, instead of an object type.

这是一个比@gonchuki 的答案稍微简洁的答案,并将其转换为实际数组,而不是对象类型。

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

A use case of this is taking all checked checkboxes and joining them into the hash of the URL, like so:

一个用例是将所有选中的复选框加入到 URL 的哈希中,如下所示:

window.location.hash = $('input:checked').map(function() {
    return $(this).attr('id');
}).toArray().join(',');

回答by Chris W.

Those interested in "beautiful" Javascript should probably check out CoffeeScript, a language which compiles to Javascript. It essentially exists because Javascript is missing things like list comprehension.

那些对“漂亮” Javascript 感兴趣的人可能应该查看CoffeeScript,这是一种编译为 Javascript 的语言。它的存在本质上是因为 Javascript 缺少诸如列表理解之类的东西。

In particular, Coffeescript's list comprehension is even more flexible than Python's. See the list comprehension docs here.

特别是,Coffeescript 的列表理解比 Python 的更灵活。请参阅此处列表理解文档

For instance this code would result in an array of nameattributes of inputelements.

例如,此代码将name生成input元素属性数组。

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

A potential downside however is the resulting Javascript is verbose (and IMHO confusing):

然而,一个潜在的缺点是由此产生的 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;
  })()
];

回答by Ben Lesh

A list comprehension has a few parts to it.

列表理解有几个部分。

  1. Selecting a set of something
  2. From a set of Something
  3. Filtered by Something
  1. 选择一组东西
  2. 从一组东西
  3. 被某物过滤

In JavaScript, as of ES5 (so I think that's supported in IE9+, Chrome and FF) you can use the mapand filterfunctions on an array.

在 JavaScript 中,从 ES5 开始(所以我认为 IE9+、Chrome 和 FF 支持),您可以在数组上使用mapfilter函数。

You can do this with map and filter:

您可以使用 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"]

That's about as good as it's going to get without setting up additional methods or using another framework.

这与不设置其他方法或使用其他框架一样好。

As for the specific question...

至于具体问题...

With jQuery:

使用 jQuery:

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

Without jQuery:

没有 jQuery:

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

[].slice.call()is just to convert the NodeListto an Array.

[].slice.call()只是将 转换NodeListArray

回答by Ben Lesh

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:

这是一个基于范围的实现,就像 Python 的 range(min, max) 此外,列表理解遵循以下形式:

[{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

最后一个人可以选择不为我的“生成”方法使用递归,因为它可以更快地完成工作。或者甚至更好地使用许多流行的 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]);
};

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': 'Hyman'}];
[(function(l){ return l; })(__(objects, 'name', [], function(x, y) { var x = x || {}; return x[y] }))];
// returns Array[1] -> ['Joe', 'Hyman']
[(function(l){ return l; })(__(0, 300, [], function(x) { return x > 10; }))];

The syntax sucks I know!

我知道语法很糟糕!

Best of luck.

祝你好运。

回答by Brian Burns

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

数组推导式是 ECMAScript 6 草案的一部分。目前(2014 年 1 月)只有 Mozilla/Firefox 的 JavaScript 实现了它们。

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#:

尽管 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

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

回答by Evan

This is an example of a place where Coffeescriptreally shines

这是Coffeescript真正闪耀的地方的一个例子

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

The equivalent Javascript would be:

等效的 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;
  })()
];