Development Tip

Javascript로 목록 이해하기

yourdevel 2020. 12. 25. 10:37
반응형

Javascript로 목록 이해하기


Javascript가 Python의 목록 이해 와 같은 작업을 수행하도록하는 가장 깨끗한 방법은 무엇입니까 ?

파이썬에서 이름이 '뽑아 내고 싶은'객체 목록이 있으면 이렇게 할 것입니다.

list_of_names = [x.name for x in list_of_objects]

자바 스크립트에서 나는 for 루프 구조를 사용하는 것 외에 더 '아름다운'방법을 실제로 보지 못합니다.

참고 : 저는 jQuery를 사용하고 있습니다. 아마도 이것을 가능하게 만드는 멋진 기능이 있습니까?

보다 구체적으로, $('input')모든 input요소 를 가져 오기 위해 jQuery 선택기를 사용한다고 가정 해 보겠습니다. 이러한 각 요소 (즉, 배열의 모든 문자열)에 대한 모든 특성 의 배열을 가장 깔끔하게 만드는 방법은 무엇입니까?nameinput$('input').attr('name')


Array.map을 사용하는 일반적인 경우 에는 자바 스크립트 1.6 (즉, IE <9를 제외한 모든 브라우저에서 작동)이 필요 하거나 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에 도입 된 배열 이해있지만 이것은 순전히 구문에 의존하며 기본적으로 부족한 브라우저에서 에뮬레이션 할 수 없습니다. 이것은 당신이 게시 한 파이썬 스 니펫에 자바 스크립트에서 얻을 수있는 가장 가까운 것입니다.


목록 이해에는 몇 가지 부분이 있습니다.

  1. 무언가 선택하기
  2. 무언가의 집합에서
  3. 무언가로 필터링 됨

JavaScript에서는 ES5 (IE9 +, Chrome 및 FF에서 지원한다고 생각합니다)부터 배열 에서 mapfilter함수를 사용할 수 있습니다 .

맵 및 필터를 사용하여이를 수행 할 수 있습니다.

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()(가) 변환 그냥 NodeListArray.


"아름다운"자바 스크립트에 관심이있는 사람들은 자바 스크립트 로 컴파일되는 언어 인 CoffeeScript를 확인해야 할 것입니다 . Javascript에는 목록 이해와 같은 것이 없기 때문에 본질적으로 존재합니다.

특히 Coffeescript의 목록 이해력은 Python보다 훨씬 유연합니다. 여기 에서 목록 이해 문서를 참조 하십시오 .

예를 들어이 코드는 요소 name속성 배열을 생성 합니다 input.

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

그러나 잠재적 인 단점은 결과 Javascript가 장황하고 IMHO가 혼란 스럽다는 것입니다.

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

따라서 파이썬의 목록 이해는 실제로 매핑과 필터링이라는 두 가지 작업을 한 번에 수행합니다. 예를 들면 :

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

예제에서 볼 수 있듯이 매핑 부분 만 원하는 경우 jQuery의지도 기능을 사용할 수 있습니다. 필터링이 필요한 경우 jQuery의 "grep"기능을 사용할 수 있습니다.


재사용 가능한 방법은 다음과 같은 작은 jQuery 플러그인을 만드는 것입니다.

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

그런 다음 다음과 같이 사용할 수 있습니다.

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

목록 이해력은 아니지만 자바 스크립트에는 존재하지 않습니다. 당신이 할 수있는 일은 자바 스크립트와 jquery를 사용하는 것뿐입니다.


배열 이해는 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]

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


예 — 목록 이해도 그리워요.

다음은 @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(',');

한 줄 접근 방식이 있으며, 목록 생성자에서 중첩 된 폐쇄 함수를 사용합니다. 그리고 시퀀스를 생성하는 데 오래 걸리는 함수입니다. 아래에 정의되어 있습니다.

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

내가 아는 구문은 짜증나!

행운을 빕니다.


이것은 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;
  })()
];

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_names array...

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

ReferenceURL : https://stackoverflow.com/questions/4964456/make-javascript-do-list-comprehension

반응형