Nesne dizisini niteliklere göre nasıl filtreleyebilirim?


473

Ben emlak ev nesneleri aşağıdaki JavaScript dizi var:

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;

Ne yapmak istiyorum "ev" nesnelerin bir alt kümesi döndürmek için nesne üzerinde bir filtre gerçekleştirmek mümkün.

Örneğin, ben dayalı filtreye yapabilmek istiyor: price, sqft, num_of_beds, ve num_of_baths.

JavaScript'te aşağıdaki sahte kod gibi bir şeyi nasıl gerçekleştirebilirim:

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

Sözdiziminin tam olarak yukarıdaki gibi olması gerekmediğini unutmayın. Bu sadece bir örnek.



3
var json = { ... }JSON, veri alışverişi için metinsel bir gösterimdir . (Daha fazla bilgi.) JavaScript kaynak kodu ile uğraşıyorsanız ve bir dize ile uğraşmıyorsanız, JSON ile uğraşmıyorsunuzdur.
TJ Crowder

1
Eval kullanmayın. Genellikle kötü bir uygulamadır ve performans sorunlarına neden olabilir. İşlemci kilitlendiği için bir projedeki birkaç kişiden kurtulmamız gerekiyordu.
SDH

Yanıtlar:


718

Array.prototype.filterYöntemi kullanabilirsiniz :

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

Canlı Örnek:

Bu yöntem yeni ECMAScript 5. Baskı standardının bir parçasıdır ve neredeyse tüm modern tarayıcılarda bulunabilir.

IE için, uyumluluk için aşağıdaki yöntemi ekleyebilirsiniz:

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
/ * nedir, thisp * /?
JGreig

2
@JGreig: İsteğe bağlı bir argümanın iletilebileceğini gösteren bir yorumdur, ECMA standardı tam olarak bu yöntemin sadece bir argüman ( Array.prototype.filter.length == 1;) beklemesi gerektiğini söylediğinden argüman doğrudan belirtilmez . İkinci bağımsız değişkeni kullandığınızda, bu this, geri arama işlevinin içindeki değer olarak kullanılır .
CMS

1
@CMS, Bu kodun çalıştığından emin misiniz? Fiyat gerçekten yüksek ve sqft / yatak / banyo gerçekten düşük olarak ayarlamak bile boş bir dizi döndürüyor. Bu kodun çalıştığından emin misiniz?
JGreig

2
@JGreig: Evet, işe yarıyor, kriterlerinizi kontrol etmelisiniz, belki pastie.org veya jsbin.com'da JSON'nuzun daha eksiksiz bir örneğini ve filtrelemek için kullandığınız kriterleri gönderebilirsiniz, böylece size daha iyi yardımcı olabilirim.
CMS

2
@CMS Cevabın yeni bir dizi döndürüldüğü gerçeğini içeriyorsa, orijinal dizi değiştirilmezse iyi olur. Bu sağlanan bağlantıda söylenmiş olsa da, bu olmadan cevap eksik veya yanlış
buluyorum


26

Alt çizgi çerçevesini tercih ederim. Nesnelerle birçok yararlı işlem önerir. Senin görevin:

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

üzerine yazılabilir:

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

Umarım sizin için yararlı olacaktır!


Bu alt çizgi nasıl çalışır ve tam olarak ne anlama gelir?
John Demetriou

4
Javascript dizilerini sorgulamak için MongoDB benzeri sözdizimini kullanan underscore-query( github.com/davidgtonge/underscore-query ) keşfettik . Yani burada kullanacaksınız_.query(homes, {price: {$lt:1000}, sqft: {$gte: 500}, num_of_beds: {$gte:2}, num_of_baths: {$gte: 2.5}}
prototip

12

Kimsenin tek satır yanıt göndermediğine şaşırdım:

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

... ve daha kolay okuyabilmeniz için:

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

2
muhtemelen sadece ok fonksiyonları ile CMS'nin cevabı ile aynı
Erich

11

İşte jquery MAP işlevini kullanarak IE8 iyi çalışan çalışma keman

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 beri jQuery.grep () kullanabilirsiniz:

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

7

Bunu oldukça kolay bir şekilde yapabilirsiniz - muhtemelen aralarından seçim yapabileceğiniz birçok uygulama vardır, ancak bu benim temel fikrim (ve muhtemelen jQuery ile bir nesne üzerinde tekrarlayabileceğiniz bazı formatlar var, bunu şu an düşünemiyorum):

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

Ve sonra bu işlevi şöyle çağırabilirsiniz:

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

Bu şekilde, tanımladığınız öngörüye bağlı olarak filtreyi çağırabilir, hatta daha küçük filtreler kullanarak birden çok kez filtreleyebilirsiniz.


Lütfen ilk pasajdaki "int length" değerini "var length" olarak değiştirin
Malay Desai

4

İhtiyaçlarınızı karşılayan bir filtre yöntemini kendiniz uygulayabilirsiniz, işte şöyle:

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

Umarım yardımcı olur!


Benim yüklem durumum çeşitli tıklamalardan değişiyor. Geçerli yüklem değerlerini nasıl saklayabilir ve istediğimde filtrem işlevine nasıl uygulayabilirim?
Malay Desai

3

Filtre yöntemlerinde yerleşik olan ve standart javascript dizisini (ve ayrıca gruplama, sıralama ve bulma) genişleten OGX.List'e göz atmalısınız . Filtreler için desteklediği operatörlerin listesi:

'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

Bu şekilde kullanabilirsiniz

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

Hatta bu şekilde

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

Veya tek bir astar olarak

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

2

Ya da sadece $.each(diziler için değil, nesneler için de çalışır) kullanabilir ve şöyle yeni bir dizi oluşturabilirsiniz:

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İşlevimi belirli istenmeyen özellik değerlerine dayalı olarak nesneleri filtrelemek için kullanıyorum . Örneğinizde değerler yerine koşulları kullanmak istediğinizi anlıyorum, ancak cevabım soru başlığı için geçerli, bu yüzden yöntemimi burada bırakmak istiyorum.

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

Böyle aktörlerin bir listeniz olduğunu varsayalım:

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

ve Holywood yıldızları olarak değerlendirilen tüm aktörleri bulmak istersiniz, uyrukları 'İngilizce', 'İtalyan', 'İspanyol', 'Yunan' değil, isimleri 'Mary' den biri olmamalı, 'Joe'. Bizzar örneği, biliyorum! Her neyse, bu koşullar kümesiyle aşağıdaki nesneyi yaratabilirsiniz:

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

Tamam, şimdi eğer ruleOut(actors, unwantedFieldsFilter)sadece

[{userName: "Bill", iş: "yıldız", dil: "Türkçe"}]

Ve Bill senin adamın, çünkü adı 'Mary', 'Joe' değil, milliyeti ['English', 'Italian', 'Spanish', 'Greek'] içinde değil, aynı zamanda bir Yıldız!

Benim yöntemimde bir seçenek var, bu applyAllFiltersvarsayılan olarak doğrudur. Bu parametrenin yanlış olarak ayarlanmasıyla ruleOut'u denerseniz, 'VE' yerine 'VEYA' filtreleme işlevi görür. Örnek: ruleOut(actors, {job:["actor"], language:["Italian"]}, false)size bir aktör veya İtalyan olmayan herkesi getirir:

[{userName: "Mary", iş: "star", dil: "Turkish"},
{userName: "Takis", job: "star", dil: "Greek"},
{userName: "Joe", job: "star", dil: "Turkish"},
{userName: "Bill", iş: "star", dil: "Turkish"}]


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

Bu lambda işlevini kullanabilirsiniz. Doğru veya yanlış döndüren koşula sahip olduğunuza göre verileri filtrelediğimizden ve gerçek dizinizin değiştirilmemesi için verileri farklı dizide toplayacağından daha fazla ayrıntı burada bulunabilir.

@JGreig Lütfen içine bakın.


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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.