javascript过滤器数组多个条件


77

我想简化对象数组。假设我有以下数组:

var users = [{
    name: 'John',
    email: 'johnson@mail.com',
    age: 25,
    address: 'USA'
    },
    {
        name: 'Tom',
        email: 'tom@mail.com',
        age: 35,
        address: 'England'
    },
    {
        name: 'Mark',
        email: 'mark@mail.com',
        age: 28,
        address: 'England'
}];

并过滤对象:

var filter = {address: 'England', name: 'Mark'};

例如,我需要按地址和名称过滤所有用户,因此我要遍历过滤器对象属性并将其检出:

function filterUsers (users, filter) {
    var result = [];
    for (var prop in filter) {
        if (filter.hasOwnProperty(prop)) {

            //at the first iteration prop will be address
            for (var i = 0; i < filter.length; i++) {
                if (users[i][prop] === filter[prop]) {
                    result.push(users[i]);
                }
            }
        }
    }
    return result;
}

因此,在第一次迭代中,当prop - address等于时,'England'两个用户将被添加到数组结果中(名称分别为Tom和Mark),但是在第二次迭代中,当prop name等于时,Mark仅将最后一个用户添加到数组结果中,但是最后我得到两个数组中的元素。

我有一个小小的想法,为什么会这样,但是仍然停留在它上面,并且找不到解决它的好方法。任何帮助都是可观的。谢谢。


为什么您要遍历用户2次?
webduvet

Answers:


111

你可以这样

var filter = {
  address: 'England',
  name: 'Mark'
};
var users = [{
    name: 'John',
    email: 'johnson@mail.com',
    age: 25,
    address: 'USA'
  },
  {
    name: 'Tom',
    email: 'tom@mail.com',
    age: 35,
    address: 'England'
  },
  {
    name: 'Mark',
    email: 'mark@mail.com',
    age: 28,
    address: 'England'
  }
];


users= users.filter(function(item) {
  for (var key in filter) {
    if (item[key] === undefined || item[key] != filter[key])
      return false;
  }
  return true;
});

console.log(users)


这是一个很好的选择,但实际上我正在遇到Uncaught ReferenceError:未定义过滤器
Leandro

3
您应该为过滤器变量选择其他名称。给变量提供受保护的名称是一种不好的编码习惯。特别是由于您最终在以后使用该受保护名称的情况下,需要几行来调用Array.prototype.filter方法。
Nadav

好答案。当您想基于多个条件进行过滤时该怎么办?例如:var filter_address = ['England','UK']; var filter_name = ['Tom','Anne']; ?
andrussk

1
@andrussk var country = [“ England”,“ UK”],名称= [“ Tom”,“ Anne”]; users.filter(el =>(country.indexOf(el.address)> = 0 && names.indexOf(el.name)> = 0)));
Anuj Srivastava

该死的生活品味
COOL GUY

28

如果您知道过滤器的名称,则可以一行完成。

users = users.filter(obj => obj.name == filter.name && obj.address == filter.address)

7
这假设您同时拥有名称和地址作为过滤器
pixelknitter18年

1
@EddieFreeman,如果不知道将拥有哪些过滤器,您将如何解决?
cullanrocks

24

享受简洁代码的人的另一种选择。

:该过滤方法可以采取额外的这个说法,然后用箭头E6功能,我们可以重用正确得到一个不错的一行代码。

var users = [{name: 'John',email: 'johnson@mail.com',age: 25,address: 'USA'},
             {name: 'Tom',email: 'tom@mail.com',age: 35,address: 'England'},
             {name: 'Mark',email: 'mark@mail.com',age: 28,address: 'England'}];

var query = {address: "England", name: "Mark"};

var result = users.filter(search, query);

function search(user){
  return Object.keys(this).every((key) => user[key] === this[key]);
}




// |----------------------- Code for displaying results -----------------|
var element = document.getElementById('result');

function createMarkUp(data){
  Object.keys(query).forEach(function(key){
    var p = document.createElement('p');
    p.appendChild(document.createTextNode(
    key.toUpperCase() + ': ' + result[0][key]));
    element.appendChild(p);
  });
}

createMarkUp(result);
<div id="result"></div>


8

这是在过滤器中使用箭头功能的ES6版本。将其发布为答案是因为我们大多数人现在都在使用ES6,这可能会帮助读者使用箭头功能let和const以高级方式进行过滤。

const filter = {
  address: 'England',
  name: 'Mark'
};
let users = [{
    name: 'John',
    email: 'johnson@mail.com',
    age: 25,
    address: 'USA'
  },
  {
    name: 'Tom',
    email: 'tom@mail.com',
    age: 35,
    address: 'England'
  },
  {
    name: 'Mark',
    email: 'mark@mail.com',
    age: 28,
    address: 'England'
  }
];


users= users.filter(item => {
  for (let key in filter) {
    if (item[key] === undefined || item[key] != filter[key])
      return false;
  }
  return true;
});

console.log(users)


8

结合使用Array.Filter()Arrow函数,我们可以使用

users = users.filter(x => x.name =='马克'&& x.address =='英国');

这是完整的片段

// initializing list of users
var users = [{
    name: 'John',
    email: 'johnson@mail.com',
    age: 25,
    address: 'USA'
  },
  {
    name: 'Tom',
    email: 'tom@mail.com',
    age: 35,
    address: 'England'
  },
  {
    name: 'Mark',
    email: 'mark@mail.com',
    age: 28,
    address: 'England'
  }
];

//filtering the users array and saving 
//result back in users variable
users = users.filter(x => x.name == 'Mark' && x.address == 'England');


//logging out the result in console
console.log(users);


比较x.name =='Mark'可能会导致意外的类型强制
键盘战士

7

也可以这样进行:

    this.users = this.users.filter((item) => {
                return (item.name.toString().toLowerCase().indexOf(val.toLowerCase()) > -1 ||
                item.address.toLowerCase().indexOf(val.toLowerCase()) > -1 ||
                item.age.toLowerCase().indexOf(val.toLowerCase()) > -1 ||
                item.email.toLowerCase().indexOf(val.toLowerCase()) > -1);
            })

4

在lodash,

_.filter(users,{address: 'England', name: 'Mark'})

在es6中,

users.filter(o => o.address == 'England' && o.name == 'Mark')

3

我认为这可能会有所帮助。

const filters = ['a', 'b'];

const results = [
  {
    name: 'Result 1',
    category: ['a']
  },
  {
    name: 'Result 2',
    category: ['a', 'b']
  },
  {
    name: 'Result 3',
    category: ['c', 'a', 'b', 'd']
  }
];

const filteredResults = results.filter(item =>
  filters
    .map(val => item.category.indexOf(val))
    .map(val => (val > -1 ? true : false))
    .reduce((acc, cum) => acc && cum)
);

console.log(filteredResults);
  


1

功能解决方案

function applyFilters(data, filters) {
  return data.filter(item =>
    Object.keys(filters)
      .map(keyToFilterOn =>
        item[keyToFilterOn].includes(filters[keyToFilterOn]),
      )
      .reduce((x, y) => x && y, true),
  );
}

这应该做的工作

applyFilters(users, filter);


0

如果您代码的最终目的是获得过滤后的用户,则我将对for求反,user而不是在每次迭代过程中减少结果数组。

这是一个(未试用的)示例:

function filterUsers (users, filter) {
    var result = [];

    for (i=0;i<users.length;i++){
        for (var prop in filter) {
            if (users.hasOwnProperty(prop) && users[i][prop] === filter[prop]) {
                result.push(users[i]);
            }
        }
    }
    return result;
}

0

一些小助手的组成:

const filter = {address: 'England', name: 'Mark'};
console.log( 
  users.filter(and(map(propMatches)(filter)))
)

function propMatches<T>(property: string, value: any) {
  return (item: T): boolean => item[property] === value
}

function map<T>(mapper: (key: string, value: any, obj: T) => (item:T) => any) {
  return (obj: T) => {
    return Object.keys(obj).map((key) => {
      return mapper(key, obj[key], obj)
    });
  }
}

export function and<T>(predicates: ((item: T) => boolean)[]) {
  return (item: T) =>
    predicates.reduce(
        (acc: boolean, predicate: (item: T) => boolean) => {
            if (acc === undefined) {
                return !!predicate(item);
            }
            return !!predicate(item) && acc;
        },
        undefined // initial accumulator value
    );
}

这是什么语言?这是一个JavaScript问题。
mikemaccana

不,这不对。SyntaxError: Unexpected token '<'
mikemaccana19年

它是打字稿。
nils petersohn19年

0

这是一个易于理解的功能解决方案

let filtersObject = {
  address: "England",
  name: "Mark"
};

let users = [{
    name: 'John',
    email: 'johnson@mail.com',
    age: 25,
    address: 'USA'
  },
  {
    name: 'Tom',
    email: 'tom@mail.com',
    age: 35,
    address: 'England'
  },
  {
    name: 'Mark',
    email: 'mark@mail.com',
    age: 28,
    address: 'England'
  }
];

function filterUsers(users, filtersObject) {
  //Loop through all key-value pairs in filtersObject
  Object.keys(filtersObject).forEach(function(key) {
    //Loop through users array checking each userObject
    users = users.filter(function(userObject) {
      //If userObject's key:value is same as filtersObject's key:value, they stay in users array
      return userObject[key] === filtersObject[key]
    })
  });
  return users;
}

//ES6
function filterUsersES(users, filtersObject) {
  for (let key in filtersObject) {
    users = users.filter((userObject) => userObject[key] === filtersObject[key]);
  }
  return users;
}

console.log(filterUsers(users, filtersObject));
console.log(filterUsersES(users, filtersObject));


0

我发现这是另一种方法,其中filterUsers是一个返回用户排序列表的函数。

var filtersample = {address: 'England', name: 'Mark'};

filteredUsers() {
  return this.users.filter((element) => {
    return element['address'].toLowerCase().match(this.filtersample['address'].toLowerCase()) || element['name'].toLowerCase().match(this.filtersample['name'].toLowerCase());
  })
}


0
const users = [{
    name: 'John',
    email: 'johnson@mail.com',
    age: 25,
    address: 'USA'
  },
  {
    name: 'Tom',
    email: 'tom@mail.com',
    age: 35,
    address: 'England'
  },
  {
    name: 'Mark',
    email: 'mark@mail.com',
    age: 28,
    address: 'England'
  }
];

const filteredUsers = users.filter(({ name, age }) => name === 'Tom' && age === 35)

console.log(filteredUsers)


1
尽管此代码可以为问题提供解决方案,但最好添加有关其原因/工作方式的上下文。这可以帮助将来的用户学习并将该知识应用于他们自己的代码。当解释代码时,您还可能以投票的形式从用户那里获得积极的反馈。
borchvm

0

如果将过滤器对象中的值转换为数组,则将具有更大的灵活性:

var filter = {address: ['England'], name: ['Mark'] };

这样,您可以过滤“英格兰”或“苏格兰”之类的内容,这意味着结果可能包括英格兰和苏格兰的记录:

var filter = {address: ['England', 'Scotland'], name: ['Mark'] };

使用该设置,您的过滤功能可以是:

const applyFilter = (data, filter) => data.filter(obj =>
    Object.entries(filter).every(([prop, find]) => find.includes(obj[prop]))
);

// demo
var users = [{name: 'John',email: 'johnson@mail.com',age: 25,address: 'USA'},{name: 'Tom',email: 'tom@mail.com',age: 35,address: 'England'},{name: 'Mark',email: 'mark@mail.com',age: 28,address: 'England'}];var filter = {address: ['England'], name: ['Mark'] };
var filter = {address: ['England'], name: ['Mark'] };

console.log(applyFilter(users, filter));


0

如果要在中放置多个条件filter,则可以使用&&||运算符。

var product= Object.values(arr_products).filter(x => x.Status==status && x.email==user)

-1
const data = [{
    realName: 'Sean Bean',
    characterName: 'Eddard “Ned” Stark'
}, {
    realName: 'Kit Harington',
    characterName: 'Jon Snow'
}, {
    realName: 'Peter Dinklage',
    characterName: 'Tyrion Lannister'
}, {
    realName: 'Lena Headey',
    characterName: 'Cersei Lannister'
}, {
    realName: 'Michelle Fairley',
    characterName: 'Catelyn Stark'
}, {
    realName: 'Nikolaj Coster-Waldau',
    characterName: 'Jaime Lannister'
}, {
    realName: 'Maisie Williams',
    characterName: 'Arya Stark'
}];

const filterKeys = ['realName', 'characterName'];


const multiFilter = (data = [], filterKeys = [], value = '') => data.filter((item) => filterKeys.some(key => item[key].toString().toLowerCase().includes(value.toLowerCase()) && item[key]));


let filteredData = multiFilter(data, filterKeys, 'stark');

console.info(filteredData);
/* [{
  "realName": "Sean Bean",
  "characterName": "Eddard “Ned” Stark"
}, {
  "realName": "Michelle Fairley",
  "characterName": "Catelyn Stark"
}, {
  "realName": "Maisie Williams",
  "characterName": "Arya Stark"
}]
 */
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.