วิธีการกรองอาเรย์วัตถุตามคุณสมบัติ?


473

ฉันมีอาร์เรย์ 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_bedsnum_of_baths

ฉันจะทำอะไรบางอย่างใน JavaScript เช่นหลอกรหัสด้านล่าง

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

หมายเหตุไวยากรณ์ไม่จำเป็นต้องเหมือนกันทุกประการ นี่เป็นเพียงตัวอย่าง


7
นี้ดูเหมือนว่าเกือบจะเหมือนกับstackoverflow.com/questions/1694717/...
Crescent สด

3
var json = { ... }JSON เป็นข้อความเกี่ยวกับการแลกเปลี่ยนข้อมูล (เพิ่มเติมที่นี่)หากคุณกำลังจัดการกับซอร์สโค้ด JavaScript และไม่จัดการกับสตริงคุณจะไม่ได้ติดต่อกับ JSON
TJ Crowder

1
อย่าใช้ eval โดยทั่วไปแล้วการปฏิบัติที่ไม่ดีและอาจทำให้เกิดปัญหาด้านประสิทธิภาพ เราต้องกำจัดกลุ่มเหล่านั้นในโปรเจ็กต์เพราะตัวประมวลผลล็อคอยู่
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, คุณแน่ใจหรือว่ารหัสนี้ใช้งานได้? นี่เป็นการคืนอาเรย์ที่ว่างเปล่าแม้ว่าฉันจะตั้งราคาให้สูงจริงๆและตารางฟุต / เตียง / ห้องอาบน้ำก็ต่ำมาก คุณแน่ใจหรือว่ารหัสนี้ใช้งานได้?
JGreig

2
@JGreig: ใช่มันใช้งานได้คุณควรตรวจสอบเกณฑ์ของคุณบางทีคุณอาจโพสต์ตัวอย่างที่สมบูรณ์มากขึ้นของ JSON ของคุณในpastie.orgหรือjsbin.comและเกณฑ์ที่คุณใช้ในการกรองดังนั้นฉันสามารถช่วยคุณได้ดีขึ้น
CMS

2
@CMS มันจะดีถ้าคำตอบรวมถึงความจริงที่ว่าอาร์เรย์ใหม่จะถูกส่งกลับอาร์เรย์เดิมจะไม่แก้ไข แม้ว่าจะมีการกล่าวถึงในลิงก์ที่ให้ไว้ แต่ฉันพบว่าคำตอบที่ไม่สมบูรณ์หรือไม่ถูกต้อง
GWorking

29

คุณสามารถลองใช้เฟรมเวิร์กเช่น jLinq - ต่อไปนี้เป็นตัวอย่างโค้ดของการใช้ jLinq

var results = jLinq.from(data.users)
.startsWith("first", "a")
.orEndsWith("y")
.orderBy("admin", "age")
.select();

สำหรับข้อมูลเพิ่มเติมคุณสามารถไปที่ลิงค์http://www.hugoware.net/projects/jlinq


26

ฉันชอบกรอบขีดล่าง มันแสดงให้เห็นการดำเนินงานที่มีประโยชน์มากมายกับวัตถุ งานของคุณ:

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
เพิ่งค้นพบunderscore-query( github.com/davidgtonge/underscore-query ) ซึ่งใช้ไวยากรณ์เหมือน MongoDB เพื่อค้นหาอาร์เรย์ JavaScript ดังนั้นที่นี่คุณจะใช้_.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

นี่คือซอที่ใช้งานได้ซึ่งทำงานได้ดีใน IE8 โดยใช้ฟังก์ชั่น jquery MAP

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 ได้ฉันแค่คิดถึงมันไม่ได้):

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

ด้วยวิธีนี้คุณสามารถเรียกใช้ตัวกรองตามสิ่งที่คุณกำหนดหรือแม้แต่กรองหลาย ๆ ครั้งโดยใช้ตัวกรองขนาดเล็ก


โปรดเปลี่ยน "ความยาว int" เป็น "ความยาว var" ในตัวอย่างแรก
Malay Desai

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

หวังว่าจะช่วย!


เงื่อนไขเพรดิเคตของฉันเปลี่ยนไปจาก onclicks ต่างๆ จะเก็บค่าเพรดิเคตปัจจุบันและนำไปใช้กับฟังก์ชันตัวกรองได้ทุกเมื่อที่ฉันต้องการ
ภาษามลายู 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)คุณจะได้รับเท่านั้น

[{ชื่อผู้ใช้: "บิล", งาน: "ดาว", ภาษา: "ตุรกี"}]

และบิลก็เป็นคนของคุณเนื่องจากชื่อของเขาไม่ใช่หนึ่งใน 'แมรี่', 'โจ', สัญชาติของเขาไม่รวมอยู่ใน ['อังกฤษ', 'อิตาลี', 'สเปน', 'สเปน', 'กรีก'] รวมทั้งเขาเป็นดาว!

มีวิธีหนึ่งในวิธีของฉันคือapplyAllFiltersและเป็นจริงโดยค่าเริ่มต้น หากคุณพยายามที่จะปกครองออกด้วยชุดพารามิเตอร์นี้เป็นเท็จนั่นจะทำงานเป็นตัวกรอง 'หรือ' แทน 'และ' ตัวอย่าง: ruleOut(actors, {job:["actor"], language:["Italian"]}, false)จะให้ทุกคนที่ไม่ใช่นักแสดงหรืออิตาเลี่ยน:

[{ชื่อผู้ใช้: "Mary", งาน: "star", ภาษา: "Turkish"},
{ชื่อผู้ใช้: "Takis", งาน: "star", ภาษา: "Greek"},
{ชื่อผู้ใช้: "Joe", งาน: "star", ภาษา: "Turkish"},
{ชื่อผู้ใช้: "Bill", งาน: "star", ภาษา: "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);

คุณสามารถใช้ฟังก์ชั่นแลมบ์ดานี้ได้ รายละเอียดเพิ่มเติมสามารถดูได้ที่นี่เนื่องจากเรากรองข้อมูลตามที่คุณมีเงื่อนไขว่าส่งคืนจริงหรือเท็จและจะรวบรวมข้อมูลในอาร์เรย์ที่แตกต่างกันดังนั้นอาร์เรย์ที่แท้จริงของคุณจะไม่ถูกแก้ไข

@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.