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: '[email protected]',
    age: 25,
    address: 'USA'
    },
    {
        name: 'Tom',
        email: '[email protected]',
        age: 35,
        address: 'England'
    },
    {
        name: 'Mark',
        email: '[email protected]',
        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.

user3673623
quelle
Warum durchlaufen Sie Benutzer zweimal?
Webduvet

Antworten:

111

Sie können dies tun

var filter = {
  address: 'England',
  name: 'Mark'
};
var users = [{
    name: 'John',
    email: '[email protected]',
    age: 25,
    address: 'USA'
  },
  {
    name: 'Tom',
    email: '[email protected]',
    age: 35,
    address: 'England'
  },
  {
    name: 'Mark',
    email: '[email protected]',
    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)

Raghavendra
quelle
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)
Abhishek Chandran
quelle
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: '[email protected]',age: 25,address: 'USA'},
             {name: 'Tom',email: '[email protected]',age: 35,address: 'England'},
             {name: 'Mark',email: '[email protected]',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>

SoEzPz
quelle
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: '[email protected]',
    age: 25,
    address: 'USA'
  },
  {
    name: 'Tom',
    email: '[email protected]',
    age: 35,
    address: 'England'
  },
  {
    name: 'Mark',
    email: '[email protected]',
    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)

Hemadri Dasari
quelle
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: '[email protected]',
    age: 25,
    address: 'USA'
  },
  {
    name: 'Tom',
    email: '[email protected]',
    age: 35,
    address: 'England'
  },
  {
    name: 'Mark',
    email: '[email protected]',
    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);

Hamza Khanzada
quelle
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);
            })
Diogo Rodrigues
quelle
4

In lodash,

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

In es6,

users.filter(o => o.address == 'England' && o.name == 'Mark')
Richard Richie
quelle
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);
  

Coşkun Deniz
quelle
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);

Houssem Zitoun
quelle
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;
}
The_Black_Smurf
quelle
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
    );
}
nils petersohn
quelle
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: '[email protected]',
    age: 25,
    address: 'USA'
  },
  {
    name: 'Tom',
    email: '[email protected]',
    age: 35,
    address: 'England'
  },
  {
    name: 'Mark',
    email: '[email protected]',
    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));

Stax
quelle
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());
  })
}

Tangu Achilis
quelle
0
const users = [{
    name: 'John',
    email: '[email protected]',
    age: 25,
    address: 'USA'
  },
  {
    name: 'Tom',
    email: '[email protected]',
    age: 35,
    address: 'England'
  },
  {
    name: 'Mark',
    email: '[email protected]',
    age: 28,
    address: 'England'
  }
];

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

console.log(filteredUsers)

Jev Belovs
quelle
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: '[email protected]',age: 25,address: 'USA'},{name: 'Tom',email: '[email protected]',age: 35,address: 'England'},{name: 'Mark',email: '[email protected]',age: 28,address: 'England'}];var filter = {address: ['England'], name: ['Mark'] };
var filter = {address: ['England'], name: ['Mark'] };

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

Trincot
quelle
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)
R15
quelle
-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"
}]
 */
Hamo
quelle