속성을 기반으로 객체 배열을 필터링하는 방법은 무엇입니까?


472

부동산 홈 객체의 다음 JavaScript 배열이 있습니다.

var json = {
    'homes': [{
            "home_id": "1",
            "price": "925",
            "sqft": "1100",
            "num_of_beds": "2",
            "num_of_baths": "2.0",
        }, {
            "home_id": "2",
            "price": "1425",
            "sqft": "1900",
            "num_of_beds": "4",
            "num_of_baths": "2.5",
        },
        // ... (more homes) ...     
    ]
}

var xmlhttp = eval('(' + json + ')');
homes = xmlhttp.homes;

내가하고 싶은 것은 객체에 필터를 수행하여 "홈"객체의 하위 집합을 반환 할 수 있다는 것입니다.

예를 들어, 내가 기준으로 필터링 할 수 있도록하려면 : price, sqft, num_of_beds,와 num_of_baths.

아래 의사 코드와 같은 JavaScript로 무언가를 수행하려면 어떻게해야합니까?

var newArray = homes.filter(
    price <= 1000 & 
    sqft >= 500 & 
    num_of_beds >=2 & 
    num_of_baths >= 2.5 );

구문은 정확히 위와 같을 필요는 없습니다. 이것은 단지 예일뿐입니다.



3
var json = { ... }JSON은 데이터 교환을위한 텍스트 표기법 입니다. (자세한 내용은 여기를 참조하십시오.) JavaScript 소스 코드를 다루고 string을 다루지 않으면 JSON을 다루지 않는 것입니다.
TJ Crowder

1
평가를 사용하지 마십시오. 일반적으로 나쁜 습관이며 성능 문제가 발생할 수 있습니다. 프로세서가 잠기고 있었기 때문에 프로젝트에서 많은 것들을 제거해야했습니다.
SDH

답변:


718

다음 Array.prototype.filter방법을 사용할 수 있습니다 .

var newArray = homes.filter(function (el) {
  return el.price <= 1000 &&
         el.sqft >= 500 &&
         el.num_of_beds >=2 &&
         el.num_of_baths >= 2.5;
});

라이브 예 :

이 방법은 새로운 ECMAScript 5th Edition 표준 의 일부이며 거의 모든 최신 브라우저에서 찾을 수 있습니다.

IE의 경우 다음과 같은 호환성 방법을 포함 할 수 있습니다.

if (!Array.prototype.filter) {
  Array.prototype.filter = function(fun /*, thisp*/) {
    var len = this.length >>> 0;
    if (typeof fun != "function")
      throw new TypeError();

    var res = [];
    var thisp = arguments[1];
    for (var i = 0; i < len; i++) {
      if (i in this) {
        var val = this[i];
        if (fun.call(thisp, val, i, this))
          res.push(val);
      }
    }
    return res;
  };
}

8
/ *, thisp * /는 무엇입니까?
JGreig

2
@JGreig : 선택적 인수가 전달 될 수 있음을 나타내는 주석 일뿐입니다. ECMA 표준에 따르면이 메소드는 하나의 인수 ( Array.prototype.filter.length == 1;) 만 예상해야하므로 인수가 직접 지정되지 않습니다 . 두 번째 인수를 사용 this하면 콜백 함수 내부의 값 으로 사용됩니다 .
CMS

1
@CMS,이 코드가 작동합니까? 가격을 실제로 높게 설정하고 sqft / beds / baths를 실제로 낮게 설정해도 빈 배열이 반환됩니다. 이 코드가 작동합니까?
JGreig

2
@ JGreig : 예, 작동합니다. 기준을 확인해야합니다. 아마도 pastie.org 또는 jsbin.com에 JSON의 더 완벽한 예제 와 필터링하는 데 사용하는 기준을 게시하여 더 나은 도움을 줄 수 있습니다.
CMS

2
@CMS 대답에 새 배열이 반환되고 원래 배열이 수정되지 않았다는 사실이 포함되어 있으면 좋을 것입니다. 이것이 제공된 링크에서 언급되었지만, 이것이 없으면 불완전하거나 정확하지 않은 답변을 찾습니다.
GWorking


26

Underscore 프레임 워크를 선호합니다. 객체에 대한 많은 유용한 작업을 제안합니다. 당신의 작업 :

var newArray = homes.filter(
    price <= 1000 & 
    sqft >= 500 &
    num_of_beds >=2 & 
    num_of_baths >= 2.5);

다음과 같이 덮어 쓸 수 있습니다.

var newArray = _.filter (homes, function(home) {
    return home.price<=1000 && sqft>=500 && num_of_beds>=2 && num_of_baths>=2.5;
});

그것이 당신에게 도움이되기를 바랍니다!


이 밑줄은 어떻게 작동하며 정확히 무엇을 의미합니까?
John Demetriou

4
MongoDB와 유사한 구문을 사용하여 자바 스크립트 배열을 쿼리하는 방금 발견 된 underscore-query( github.com/davidgtonge/underscore-query ). 그래서 당신은 여기에서 사용할 것입니다_.query(homes, {price: {$lt:1000}, sqft: {$gte: 500}, num_of_beds: {$gte:2}, num_of_baths: {$gte: 2.5}}
프로토 타입

12

아무도 한 줄짜리 응답을 게시하지 않은 것에 놀랐습니다.

const filteredHomes = json.homes.filter(x => x.price <= 1000 && x.sqft >= 500 && x.num_of_beds >=2 && x.num_of_baths >= 2.5);

... 그리고 쉽게 읽을 수 있습니다.

const filteredHomes = json.homes.filter( x => 
  x.price <= 1000 && 
  x.sqft >= 500 && 
  x.num_of_beds >=2 && 
  x.num_of_baths >= 2.5
);

2
화살표 기능 만있는 CMS의 대답 과 동일하기 때문일 수 있습니다
Erich

11

다음은 jquery MAP 함수를 사용하여 IE8에서 올바르게 작동하는 작업 바이올린입니다.

http://jsfiddle.net/533135/Cj4j7/

json.HOMES = $.map(json.HOMES, function(val, key) {
    if (Number(val.price) <= 1000
            && Number(val.sqft) >= 500
            && Number(val.num_of_beds) >=2
            && Number(val.num_of_baths ) >= 2.5)
        return val;
});

7

jQuery 1.0부터 jQuery.grep ()를 사용할 수 있습니다.

$.grep(homes, function (h) {
  return h.price <= 1000
    && h.sqft >= 500
    && h.num_of_beds >= 2
    && h.num_of_baths >= 2.5
});

7

당신은 이것을 아주 쉽게 할 수 있습니다-아마도 당신이 선택할 수있는 많은 구현이있을 것입니다, 그러나 이것은 나의 기본 아이디어입니다 (그리고 아마도 jQuery로 객체를 반복 할 수있는 형식이있을 것입니다, 나는 지금 그것을 생각할 수 없습니다) :

function filter(collection, predicate)
{
    var result = new Array();
    var length = collection.length;

    for(var j = 0; j < length; j++)
    {
        if(predicate(collection[j]) == true)
        {
             result.push(collection[j]);
        }
    }

    return result;
}

그런 다음이 기능을 다음과 같이 호출 할 수 있습니다.

filter(json, function(element)
{
    if(element.price <= 1000 && element.sqft >= 500 && element.num_of_beds > 2 && element.num_of_baths > 2.5)
        return true;

    return false;
});

이 방법으로 정의한 술어에 따라 필터를 호출하거나 더 작은 필터를 사용하여 여러 번 필터링 할 수 있습니다.


첫 번째 코드에서 "VAR 길이"를 "INT 길이"로 변경하십시오
말레이어 데 사이

4

필요에 맞는 필터 방법을 직접 구현할 수 있습니다. 방법은 다음과 같습니다.

function myfilter(array, test){
    var passedTest =[];
    for (var i = 0; i < array.length; i++) {
       if(test( array[i]))
          passedTest.push(array[i]);
    }

    return passedTest;
}

var passedHomes = myfilter(homes,function(currentHome){
     return ((currentHome.price <= 1000 )&& (currentHome.sqft >= 500 )&&(currentHome.num_of_beds >=2 )&&(currentHome.num_of_baths >= 2.5));
});

희망이 있습니다.


다양한 클릭에서 내 조건 조건이 변경됩니다. 현재 술어 값을 저장하고 원할 때마다 myfilter 함수에 적용하는 방법은 무엇입니까?
Malay Desai

3

필터링 방법이 내장되어 있고 표준 자바 스크립트 배열 (및 그룹화, 정렬 및 찾기)을 확장하는 OGX.List 를 확인해야합니다 . 필터에 대해 지원하는 연산자 목록은 다음과 같습니다.

'eq' //Equal to
'eqjson' //For deep objects, JSON comparison, equal to
'neq' //Not equal to
'in' //Contains
'nin' //Doesn't contain
'lt' //Lesser than
'lte' //Lesser or equal to
'gt' //Greater than
'gte' //Greater or equal to
'btw' //Between, expects value to be array [_from_, _to_]
'substr' //Substring mode, equal to, expects value to be array [_from_, _to_, _niddle_]
'regex' //Regex match

이런 식으로 사용할 수 있습니다

  let list = new OGX.List(your_array);
  list.addFilter('price', 'btw', 100, 500);
  list.addFilter('sqft', 'gte', 500);
  let filtered_list = list.filter();

아니면 이런 식으로

  let list = new OGX.List(your_array);
  let filtered_list = list.get({price:{btw:[100,500]}, sqft:{gte:500}});

또는 하나의 라이너로

   let filtered_list = new OGX.List(your_array).get({price:{btw:[100,500]}, sqft:{gte:500}});

2

또는 간단하게 $.each(배열뿐만 아니라 객체에서도 작동) 다음과 같이 새 배열을 만들 수 있습니다.

var json = {
    'homes': [{
            "home_id": "1",
            "price": "925",
            "sqft": "1100",
            "num_of_beds": "2",
            "num_of_baths": "2.0",
        }, {
            "home_id": "2",
            "price": "1425",
            "sqft": "1900",
            "num_of_beds": "4",
            "num_of_baths": "2.5",
        },
        // ... (more homes) ...     
        {
            "home_id": "3-will-be-matched",
            "price": "925",
            "sqft": "1000",
            "num_of_beds": "2",
            "num_of_baths": "2.5",
        },
    ]
}

var homes = [];
$.each(json.homes, function(){
    if (this.price <= 1000
        && this.sqft >= 500
        && this.num_of_beds >= 2
        && this.num_of_baths >= 2.5
    ) {
        homes.push(this);
    }
});

2

원하지 않는 특정 속성 값을ruleOut 기반으로 객체를 필터링 하는 데 내 기능을 사용 합니다. 귀하의 예에서 값 대신 조건을 사용하고 싶지만 내 대답은 질문 제목에 유효하므로 내 방법을 여기에 남겨두고 싶습니다.

function ruleOut(arr, filterObj, applyAllFilters=true) {    
    return arr.filter( row => {            
        for (var field in filterObj) {
            var val = row[field];
            if (val) {                    
                if (applyAllFilters && filterObj[field].indexOf(val) > -1) return false;                
                else if (!applyAllFilters) {                        
                    return filterObj[field].filter(function(filterValue){ 
                        return (val.indexOf(filterValue)>-1);
                    }).length == 0;                 
                }
            }
        }
        return true;
    });
}

다음과 같은 배우 목록이 있다고 가정 해보십시오.

let actors = [
  {userName:"Mary", job:"star", language:"Turkish"},
  {userName:"John", job:"actor", language:"Turkish"},
  {userName:"Takis", job:"star", language:"Greek"},
  {userName:"Joe", job:"star", language:"Turkish"},
  {userName:"Bill", job:"star", language:"Turkish"}
];

Holywood 등급으로 평가 된 모든 배우를 찾으려면 국적은 '영어', '이탈리아어', '스페인어', '그리스어'중 하나가 아니어야하며 이름은 '메리'가 아니어야합니다. '조'. Bizzar 예, 알고 있습니다! 어쨌든 해당 조건 세트를 사용하여 다음 오브젝트를 작성합니다.

let unwantedFieldsFilter= { 
  userName: ['Mary', 'Joe'],    
  job: ['actor'],   
  language: ['English', 'Italian', 'Spanish', 'Greek']  
};

좋아, 이제 ruleOut(actors, unwantedFieldsFilter)너만 얻을 수 있다면

[{userName : "청구서", 직업 : "star", 언어 : "터키어"}]

그의 이름은 'Mary', 'Joe'중 하나가 아니기 때문에 Bill은 당신의 남자입니다. 그의 국적은 [ 'English', 'Italian', 'Spanish', 'Greek']에 포함되지 않았으며 그는 별이기도합니다!

내 방법에는 하나의 옵션이 applyAllFilters있으며 기본적으로 true입니다. 이 매개 변수가 false로 설정된 상태에서 ruleOut을 시도하면 'AND'대신 'OR'필터링으로 작동합니다. 예 : ruleOut(actors, {job:["actor"], language:["Italian"]}, false)배우 또는 이탈리아어가 아닌 모든 사람을 얻을 수 있습니다.

[{userName : "Mary", 직업 : "star", 언어 : "터키어"},
{userName : "Takis", 직업 : "star", 언어 : "Greek"},
{userName : "Joe", 직업 : "star", 언어 : "터키어"},
{userName : "청구서", 직업 : "star", 언어 : "터키어"}]


1
var filterHome = homes.filter(home =>
  return (home.price <= 999 &&
         home.num_of_baths >= 2.5 &&
         home.num_of_beds >=2 &&
         home.sqft >= 998));
console.log(filterHome);

이 람다 기능을 사용할 수 있습니다. true 또는 false를 반환하는 조건이 있고 실제 배열이 수정되지 않도록 다른 배열에서 데이터를 수집하므로 조건에 따라 데이터를 필터링하므로 자세한 내용을 여기에서 찾을 수 있습니다.

@JGreig 살펴보세요.


1
const x = JSON.stringify(data);
const y = 'search text';

const data = x.filter(res => {
        return(JSON.stringify(res).toLocaleLowerCase()).match(x.toLocaleLowerCase());
      });

0
const state.contactList = [{
    name: 'jane',
    email: 'jane@gmail.com'
  },{},{},...]

const fileredArray = state.contactsList.filter((contactItem) => {
  const regex = new RegExp(`${action.payload}`, 'gi');
  return contactItem.nameProperty.match(regex) || 
    contactItem.emailProperty.match(regex);
});


// contactList: all the contacts stored in state
// action.payload: whatever typed in search field
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.