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


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.