Javascript Filter Array mehrere Bedingungen


77

Ich möchte eine Reihe von Objekten vereinfachen. Nehmen wir an, ich habe folgendes Array:

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

Und Filterobjekt:

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

Zum Beispiel muss ich alle Benutzer nach Adresse und Name filtern, damit ich die Eigenschaften des Filterobjekts durchlaufe und es auschecke:

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

Während der ersten Iteration, wenn prop - addressgleich ist, werden 'England'zwei Benutzer zum Array-Ergebnis hinzugefügt (mit dem Namen Tom und Mark), aber bei der zweiten Iteration, wenn prop namegleich ist, sollte Marknur der letzte Benutzer zum Array-Ergebnis hinzugefügt werden, aber am Ende habe ich zwei Elemente im Array.

Ich habe eine kleine Vorstellung davon, warum es passiert, bin aber immer noch dabei geblieben und konnte keine gute Lösung finden, um das Problem zu beheben. Jede Hilfe ist spürbar. Vielen Dank.


Warum durchlaufen Sie Benutzer zweimal?
Webduvet

Antworten:


111

Sie können dies tun

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)


Dies ist gut, aber tatsächlich bekomme ich Uncaught ReferenceError: Filter ist nicht definiert
Leandro

3
Sie sollten einen anderen Namen für Ihre Filtervariable wählen. Es ist eine schlechte Codierungspraxis, Ihren Variablen geschützte Namen zu geben. Zumal Sie diesen geschützten Namen einige Zeilen später verwenden, um die Methode Array.prototype.filter aufzurufen.
Nadav

Gute Antwort. Was ist, wenn Sie nach mehreren Kriterien filtern möchten, z. B.: Var filter_address = ['England', 'UK']; var filter_name = ['Tom', 'Anne']; ?
Andrussk

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

Freaking Lebensgenuss
Cool Guy

28

Wenn Sie den Namen der Filter kennen, können Sie dies in einer Zeile tun.

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

7
Dies setzt voraus, dass Sie sowohl Name als auch Adresse als Filter haben
Pixelknitter

1
@EddieFreeman Wie würden Sie das lösen, wenn Sie nicht wüssten, welche Filter Sie haben würden?
Cullanrocks

24

Eine weitere Einstellung für diejenigen unter Ihnen, die sich für prägnanten Code interessieren.

HINWEIS : Die FILTER Verfahren ein zusätzliches nehmen können dieses Argument, dann einen E6 Pfeil Funktion wir die richtigen wiederverwenden können dieses einen schönen Einzeiler zu bekommen.

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

Hier ist die ES6-Version der Verwendung der Pfeilfunktion im Filter. Dies als Antwort zu veröffentlichen, da die meisten von uns heutzutage ES6 verwenden und den Lesern möglicherweise dabei helfen, mithilfe der Pfeilfunktion let und const auf erweiterte Weise zu filtern.

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

Mit Array.filter () mit Pfeil - Funktionen können wir erreichen dies mit

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

Hier ist das komplette Snippet

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


Vergleich x.name == 'Mark' kann zu unerwartetem Zwang führen
Keyboard-Warrior

7

Kann auch so gemacht werden:

    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

In lodash,

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

In es6,

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

3

Ich denke, das könnte helfen.

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

funktionale Lösung

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

das sollte den Job machen

applyFilters(users, filter);


0

Wenn die Endgültigkeit Ihres Codes darin besteht, den gefilterten Benutzer zu erhalten, würde ich das umkehren for, um userdas Ergebnisarray während jeder Iteration auszuwerten, anstatt es zu reduzieren.

Hier ein (ungetestetes) Beispiel:

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

mit der Zusammensetzung einiger kleiner Helfer:

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

Welche Sprache ist das? Dies ist eine JavaScript-Frage.
Mikemaccana

Nein, ist es nicht. SyntaxError: Unexpected token '<'
Mikemaccana

es ist maschinenschrift.
Nils Petersohn

0

Dies ist eine leicht verständliche funktionale Lösung

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

Dies ist eine andere Methode, die ich herausgefunden habe, wobei filteredUsers eine Funktion ist, die die sortierte Liste der Benutzer zurückgibt.

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
Obwohl dieser Code eine Lösung für die Frage bietet, ist es besser, einen Kontext hinzuzufügen, warum / wie er funktioniert. Dies kann zukünftigen Benutzern helfen, zu lernen und dieses Wissen auf ihren eigenen Code anzuwenden. Es ist auch wahrscheinlich, dass Sie positive Rückmeldungen von Benutzern in Form von Upvotes erhalten, wenn der Code erklärt wird.
Borchvm

0

Sie haben mehr Flexibilität, wenn Sie die Werte in Ihrem Filterobjekt in Arrays umwandeln:

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

Auf diese Weise können Sie nach Dingen wie "England" oder "Schottland" filtern. Dies bedeutet, dass die Ergebnisse möglicherweise Datensätze für England und für Schottland enthalten:

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

Mit diesem Setup kann Ihre Filterfunktion sein:

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

Wenn Sie mehrere Bedingungen in setzen wollen filter, können Sie &&und ||Betreiber.

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"
}]
 */
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.